KDChartAbstractDiagram.cpp

Go to the documentation of this file.
00001 /****************************************************************************
00002 ** Copyright (C) 2001-2011 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         // we only a solid line surrounding the markers
00616         QPen painterPen( pen );
00617         painterPen.setStyle( Qt::SolidLine );
00618         painter->setPen( PrintingParameters::scalePen( painterPen ) );
00619         painter->setBrush( brush );
00620         painter->setRenderHint ( QPainter::Antialiasing );
00621         painter->translate( pos );
00622         switch ( markerAttributes.markerStyle() ) {
00623             case MarkerAttributes::MarkerCircle:
00624                 painter->drawEllipse( QRectF( 0 - maSize.height()/2, 0 - maSize.width()/2,
00625                             maSize.height(), maSize.width()) );
00626                 break;
00627             case MarkerAttributes::MarkerSquare:
00628                 {
00629                     QRectF rect( 0 - maSize.width()/2, 0 - maSize.height()/2,
00630                                 maSize.width(), maSize.height() );
00631                     painter->drawRect( rect );
00632                     break;
00633                 }
00634             case MarkerAttributes::MarkerDiamond:
00635                 {
00636                     QVector <QPointF > diamondPoints;
00637                     QPointF top, left, bottom, right;
00638                     top    = QPointF( 0, 0 - maSize.height()/2 );
00639                     left   = QPointF( 0 - maSize.width()/2, 0 );
00640                     bottom = QPointF( 0, maSize.height()/2 );
00641                     right  = QPointF( maSize.width()/2, 0 );
00642                     diamondPoints << top << left << bottom << right;
00643                     painter->drawPolygon( diamondPoints );
00644                     break;
00645                 }
00646             // both handled on top of the method:
00647             case MarkerAttributes::Marker1Pixel:
00648             case MarkerAttributes::Marker4Pixels:
00649                     break;
00650             case MarkerAttributes::MarkerRing:
00651                 {
00652                     painter->setPen( PrintingParameters::scalePen( QPen( brush.color() ) ) );
00653                     painter->setBrush( Qt::NoBrush );
00654                     painter->drawEllipse( QRectF( 0 - maSize.height()/2, 0 - maSize.width()/2,
00655                                         maSize.height(), maSize.width()) );
00656                     break;
00657                 }
00658             case MarkerAttributes::MarkerCross:
00659                 {
00660                     // Note: Markers can have outline,
00661                     //       so just drawing two rects is NOT the solution here!
00662                     const qreal w02 = maSize.width() * 0.2;
00663                     const qreal w05 = maSize.width() * 0.5;
00664                     const qreal h02 = maSize.height()* 0.2;
00665                     const qreal h05 = maSize.height()* 0.5;
00666                     QVector <QPointF > crossPoints;
00667                     QPointF p[12];
00668                     p[ 0] = QPointF( -w02, -h05 );
00669                     p[ 1] = QPointF(  w02, -h05 );
00670                     p[ 2] = QPointF(  w02, -h02 );
00671                     p[ 3] = QPointF(  w05, -h02 );
00672                     p[ 4] = QPointF(  w05,  h02 );
00673                     p[ 5] = QPointF(  w02,  h02 );
00674                     p[ 6] = QPointF(  w02,  h05 );
00675                     p[ 7] = QPointF( -w02,  h05 );
00676                     p[ 8] = QPointF( -w02,  h02 );
00677                     p[ 9] = QPointF( -w05,  h02 );
00678                     p[10] = QPointF( -w05, -h02 );
00679                     p[11] = QPointF( -w02, -h02 );
00680                     for( int i=0; i<12; ++i )
00681                         crossPoints << p[i];
00682                     crossPoints << p[0];
00683                     painter->drawPolygon( crossPoints );
00684                     break;
00685                 }
00686             case MarkerAttributes::MarkerFastCross:
00687                 {
00688                     QPointF left, right, top, bottom;
00689                     left  = QPointF( -maSize.width()/2, 0 );
00690                     right = QPointF( maSize.width()/2, 0 );
00691                     top   = QPointF( 0, -maSize.height()/2 );
00692                     bottom= QPointF( 0, maSize.height()/2 );
00693                     painter->setPen( PrintingParameters::scalePen( QPen( brush.color() ) ) );
00694                     painter->drawLine( left, right );
00695                     painter->drawLine(  top, bottom );
00696                     break;
00697                 }
00698             case MarkerAttributes::NoMarker:
00699                 break;
00700             default:
00701                 Q_ASSERT_X ( false, "paintMarkers()",
00702                             "Type item does not match a defined Marker Type." );
00703         }
00704     }
00705     painter->setPen( oldPen );
00706 }
00707 
00708 void AbstractDiagram::paintMarkers( QPainter* painter )
00709 {
00710     if ( !checkInvariants() ) return;
00711     const int rowCount = model()->rowCount(rootIndex());
00712     const int columnCount = model()->columnCount(rootIndex());
00713     for ( int i=datasetDimension()-1; i<columnCount; i += datasetDimension() ) {
00714        for ( int j=0; j< rowCount; ++j ) {
00715            const QModelIndex index = model()->index( j, i, rootIndex() );
00716            double value = model()->data( index ).toDouble();
00717            const QPointF pos = coordinatePlane()->translate( QPointF( j, value ) );
00718            paintMarker( painter, index, pos );
00719        }
00720     }
00721 }
00722 
00723 
00724 void AbstractDiagram::setPen( const QModelIndex& index, const QPen& pen )
00725 {
00726     attributesModel()->setData(
00727         conditionallyMapFromSource( index ),
00728         qVariantFromValue( pen ), DatasetPenRole );
00729     emit propertiesChanged();
00730 }
00731 
00732 void AbstractDiagram::setPen( const QPen& pen )
00733 {
00734     attributesModel()->setModelData(
00735         qVariantFromValue( pen ), DatasetPenRole );
00736     emit propertiesChanged();
00737 }
00738 
00739 void AbstractDiagram::setPen( int dataset, const QPen& pen )
00740 {
00741     d->setDatasetAttrs( dataset, qVariantFromValue( pen ), DatasetPenRole );
00742     emit propertiesChanged();
00743 }
00744 
00745 QPen AbstractDiagram::pen() const
00746 {
00747     return qVariantValue<QPen>(
00748         attributesModel()->data( DatasetPenRole ) );
00749 }
00750 
00751 QPen AbstractDiagram::pen( int dataset ) const
00752 {
00753     const QVariant penSettings( d->datasetAttrs( dataset, DatasetPenRole ) );
00754     if( penSettings.isValid() )
00755         return qVariantValue< QPen >( penSettings );
00756     return pen();
00757 }
00758 
00759 QPen AbstractDiagram::pen( const QModelIndex& index ) const
00760 {
00761     return qVariantValue<QPen>(
00762         attributesModel()->data(
00763             conditionallyMapFromSource( index ),
00764             DatasetPenRole ) );
00765 }
00766 
00767 void AbstractDiagram::setBrush( const QModelIndex& index, const QBrush& brush )
00768 {
00769     attributesModel()->setData(
00770         conditionallyMapFromSource( index ),
00771         qVariantFromValue( brush ), DatasetBrushRole );
00772     emit propertiesChanged();
00773 }
00774 
00775 void AbstractDiagram::setBrush( const QBrush& brush )
00776 {
00777     attributesModel()->setModelData(
00778         qVariantFromValue( brush ), DatasetBrushRole );
00779     emit propertiesChanged();
00780 }
00781 
00782 void AbstractDiagram::setBrush( int dataset, const QBrush& brush )
00783 {
00784     d->setDatasetAttrs( dataset, qVariantFromValue( brush ), DatasetBrushRole );
00785     emit propertiesChanged();
00786 }
00787 
00788 QBrush AbstractDiagram::brush() const
00789 {
00790     return qVariantValue<QBrush>(
00791         attributesModel()->data( DatasetBrushRole ) );
00792 }
00793 
00794 QBrush AbstractDiagram::brush( int dataset ) const
00795 {
00796     const QVariant brushSettings( d->datasetAttrs( dataset, DatasetBrushRole ) );
00797     if( brushSettings.isValid() )
00798         return qVariantValue< QBrush >( brushSettings );
00799     return brush();
00800 }
00801 
00802 QBrush AbstractDiagram::brush( const QModelIndex& index ) const
00803 {
00804     return qVariantValue<QBrush>(
00805         attributesModel()->data( conditionallyMapFromSource( index ), DatasetBrushRole ) );
00806 }
00807 
00814 void AbstractDiagram::setUnitPrefix( const QString& prefix, int column, Qt::Orientation orientation )
00815 {
00816     d->unitPrefixMap[ column ][ orientation ]= prefix;
00817 }
00818 
00824 void AbstractDiagram::setUnitPrefix( const QString& prefix, Qt::Orientation orientation )
00825 {
00826     d->unitPrefix[ orientation ] = prefix;
00827 }
00828 
00835 void AbstractDiagram::setUnitSuffix( const QString& suffix, int column, Qt::Orientation orientation )
00836 {
00837     d->unitSuffixMap[ column ][ orientation ]= suffix;
00838 }
00839 
00845 void AbstractDiagram::setUnitSuffix( const QString& suffix, Qt::Orientation orientation )
00846 {
00847     d->unitSuffix[ orientation ] = suffix;
00848 }
00849 
00857 QString AbstractDiagram::unitPrefix( int column, Qt::Orientation orientation, bool fallback ) const
00858 {
00859     if( !fallback || d->unitPrefixMap[ column ].contains( orientation ) )
00860         return d->unitPrefixMap[ column ][ orientation ];
00861     return d->unitPrefix[ orientation ];
00862 }
00863 
00868 QString AbstractDiagram::unitPrefix( Qt::Orientation orientation ) const
00869 {
00870     return d->unitPrefix[ orientation ];
00871 }
00872 
00880 QString AbstractDiagram::unitSuffix( int column, Qt::Orientation orientation, bool fallback ) const
00881 {
00882     if( !fallback || d->unitSuffixMap[ column ].contains( orientation ) )
00883         return d->unitSuffixMap[ column ][ orientation ];
00884     return d->unitSuffix[ orientation ];
00885 }
00886 
00891 QString AbstractDiagram::unitSuffix( Qt::Orientation orientation ) const
00892 {
00893     return d->unitSuffix[ orientation ];
00894 }
00895 
00896 // implement QAbstractItemView:
00897 QRect AbstractDiagram::visualRect( const QModelIndex &index ) const
00898 {
00899     return d->reverseMapper.boundingRect( index.row(), index.column() ).toRect();
00900 }
00901 
00902 void AbstractDiagram::scrollTo(const QModelIndex &, ScrollHint )
00903 {}
00904 
00905 // indexAt ... down below
00906 
00907 QModelIndex AbstractDiagram::moveCursor(CursorAction, Qt::KeyboardModifiers )
00908 { return QModelIndex(); }
00909 
00910 int AbstractDiagram::horizontalOffset() const
00911 { return 0; }
00912 
00913 int AbstractDiagram::verticalOffset() const
00914 { return 0; }
00915 
00916 bool AbstractDiagram::isIndexHidden(const QModelIndex &) const
00917 { return true; }
00918 
00919 void AbstractDiagram::setSelection(const QRect& rect , QItemSelectionModel::SelectionFlags command )
00920 {
00921     const QModelIndexList indexes = d->indexesIn( rect );
00922     QItemSelection selection;
00923     KDAB_FOREACH( const QModelIndex& index, indexes )
00924     {
00925         selection.append( QItemSelectionRange( index ) );
00926     }
00927     selectionModel()->select( selection, command );
00928 }
00929 
00930 QRegion AbstractDiagram::visualRegionForSelection(const QItemSelection &selection) const
00931 {
00932     QPolygonF polygon;
00933     KDAB_FOREACH( const QModelIndex& index, selection.indexes() )
00934     {
00935         polygon << d->reverseMapper.polygon(index.row(), index.column());
00936     }
00937     return polygon.isEmpty() ? QRegion() : QRegion( polygon.toPolygon() );
00938 }
00939 
00940 QRegion AbstractDiagram::visualRegion(const QModelIndex &index) const
00941 {
00942     QPolygonF polygon = d->reverseMapper.polygon(index.row(), index.column());
00943     return polygon.isEmpty() ? QRegion() : QRegion( polygon.toPolygon() );
00944 }
00945 
00946 void KDChart::AbstractDiagram::useDefaultColors( )
00947 {
00948     d->attributesModel->setPaletteType( AttributesModel::PaletteTypeDefault );
00949 }
00950 
00951 void KDChart::AbstractDiagram::useSubduedColors( )
00952 {
00953     d->attributesModel->setPaletteType( AttributesModel::PaletteTypeSubdued );
00954 }
00955 
00956 void KDChart::AbstractDiagram::useRainbowColors( )
00957 {
00958     d->attributesModel->setPaletteType( AttributesModel::PaletteTypeRainbow );
00959 }
00960 
00961 QStringList AbstractDiagram::itemRowLabels() const
00962 {
00963     QStringList ret;
00964     if( model() ){
00965         //qDebug() << "AbstractDiagram::itemRowLabels(): " << attributesModel()->rowCount(attributesModelRootIndex()) << "entries";
00966         const int rowCount = attributesModel()->rowCount(attributesModelRootIndex());
00967         for( int i = 0; i < rowCount; ++i ){
00968             //qDebug() << "item row label: " << attributesModel()->headerData( i, Qt::Vertical, Qt::DisplayRole ).toString();
00969             ret << unitPrefix( i, Qt::Horizontal, true ) +
00970                    attributesModel()->headerData( i, Qt::Vertical, Qt::DisplayRole ).toString() +
00971                    unitSuffix( i, Qt::Horizontal, true );
00972         }
00973     }
00974     return ret;
00975 }
00976 
00977 QStringList AbstractDiagram::datasetLabels() const
00978 {
00979     QStringList ret;
00980     if( model() == 0 )
00981         return ret;
00982     
00983     const int columnCount = attributesModel()->columnCount(attributesModelRootIndex());
00984     for( int i = 0; i < columnCount; i += datasetDimension() )
00985         ret << attributesModel()->headerData( i, Qt::Horizontal, Qt::DisplayRole ).toString();
00986     
00987     return ret;
00988 }
00989 
00990 QList<QBrush> AbstractDiagram::datasetBrushes() const
00991 {
00992     QList<QBrush> ret;
00993     if( model() == 0 )
00994         return ret;
00995 
00996     const int datasetCount = attributesModel()->columnCount(attributesModelRootIndex()) / datasetDimension();
00997     for ( int dataset = 0; dataset < datasetCount; dataset++ )
00998         ret << brush( dataset );
00999 
01000     return ret;
01001 }
01002 
01003 QList<QPen> AbstractDiagram::datasetPens() const
01004 {
01005     QList<QPen> ret;
01006     if( model() == 0 )
01007         return ret;
01008     
01009     const int datasetCount = attributesModel()->columnCount(attributesModelRootIndex()) / datasetDimension();
01010     for ( int dataset = 0; dataset < datasetCount; dataset++ )
01011         ret << pen( dataset );
01012     
01013     return ret;
01014 }
01015 
01016 QList<MarkerAttributes> AbstractDiagram::datasetMarkers() const
01017 {
01018     QList<MarkerAttributes> ret;
01019     if( model() == 0 )
01020         return ret;
01021     
01022     const int datasetCount = attributesModel()->columnCount(attributesModelRootIndex()) / datasetDimension();
01023     for ( int dataset = 0; dataset < datasetCount; dataset++ )
01024         ret << dataValueAttributes( dataset ).markerAttributes();
01025 
01026     return ret;
01027 }
01028 
01029 bool AbstractDiagram::checkInvariants( bool justReturnTheStatus ) const
01030 {
01031     if( ! justReturnTheStatus ){
01032         Q_ASSERT_X ( model(), "AbstractDiagram::checkInvariants()",
01033                     "There is no usable model set, for the diagram." );
01034 
01035         Q_ASSERT_X ( coordinatePlane(), "AbstractDiagram::checkInvariants()",
01036                     "There is no usable coordinate plane set, for the diagram." );
01037     }
01038     return model() && coordinatePlane();
01039 }
01040 
01041 int AbstractDiagram::datasetDimension( ) const
01042 {
01043     return d->datasetDimension;
01044 }
01045 
01046 void AbstractDiagram::setDatasetDimension( int dimension )
01047 {
01048     Q_UNUSED( dimension );
01049     qDebug() << "Setting the dataset dimension using AbstractDiagram::setDatasetDimension is obsolete. Use the specific diagram types instead.";
01050 }
01051 
01052 void AbstractDiagram::setDatasetDimensionInternal( int dimension )
01053 {
01054     Q_ASSERT( dimension != 0 );
01055     
01056     if ( d->datasetDimension == dimension ) return;
01057     d->datasetDimension = dimension;
01058     setDataBoundariesDirty();
01059     emit layoutChanged( this );
01060 }
01061 
01062 double AbstractDiagram::valueForCell( int row, int column ) const
01063 {
01064     return d->attributesModel->data(
01065             d->attributesModel->index( row, column, attributesModelRootIndex() ) ).toDouble();
01066 }
01067 
01068 void AbstractDiagram::update() const
01069 {
01070     //qDebug("KDChart::AbstractDiagram::update() called");
01071     if( d->plane )
01072         d->plane->update();
01073 }
01074 
01075 QModelIndex AbstractDiagram::indexAt( const QPoint& point ) const
01076 {
01077     return d->indexAt( point );
01078 }
01079 
01080 QModelIndexList AbstractDiagram::indexesAt( const QPoint& point ) const
01081 {
01082     return d->indexesAt( point );
01083 }
01084 
 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/