KD Chart 2  [rev.2.5]
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 #include "KDChartPainterSaver_p.h"
00043 
00044 #include <KDABLibFakes>
00045 
00046 #include <limits>
00047 
00048 using namespace KDChart;
00049 
00050 #define d d_func()
00051 
00052 AbstractDiagram::AbstractDiagram ( QWidget* parent, AbstractCoordinatePlane* plane )
00053     : QAbstractItemView ( parent ), _d( new Private() )
00054 {
00055     _d->init( plane );
00056     init();
00057 }
00058 
00059 AbstractDiagram::~AbstractDiagram()
00060 {
00061     emit aboutToBeDestroyed();
00062     delete _d;
00063 }
00064 
00065 void AbstractDiagram::init()
00066 {
00067     _d->diagram = this;
00068     d->reverseMapper.setDiagram( this );
00069 }
00070 
00071 
00072 bool AbstractDiagram::compare( const AbstractDiagram* other ) const
00073 {
00074     if( other == this ) return true;
00075     if ( !other ) {
00076         return false;
00077     }
00078     return  // compare QAbstractScrollArea properties
00079             (horizontalScrollBarPolicy() == other->horizontalScrollBarPolicy()) &&
00080             (verticalScrollBarPolicy()   == other->verticalScrollBarPolicy()) &&
00081             // compare QFrame properties
00082             (frameShadow()  == other->frameShadow()) &&
00083             (frameShape()   == other->frameShape()) &&
00084 // frameWidth is a read-only property defined by the style, it should not be in here:
00085             // (frameWidth()   == other->frameWidth()) &&
00086             (lineWidth()    == other->lineWidth()) &&
00087             (midLineWidth() == other->midLineWidth()) &&
00088             // compare QAbstractItemView properties
00089             (alternatingRowColors()  == other->alternatingRowColors()) &&
00090             (hasAutoScroll()         == other->hasAutoScroll()) &&
00091 #if QT_VERSION > 0x040199
00092             (dragDropMode()          == other->dragDropMode()) &&
00093             (dragDropOverwriteMode() == other->dragDropOverwriteMode()) &&
00094             (horizontalScrollMode()  == other->horizontalScrollMode ()) &&
00095             (verticalScrollMode()    == other->verticalScrollMode()) &&
00096 #endif
00097             (dragEnabled()           == other->dragEnabled()) &&
00098             (editTriggers()          == other->editTriggers()) &&
00099             (iconSize()              == other->iconSize()) &&
00100             (selectionBehavior()     == other->selectionBehavior()) &&
00101             (selectionMode()         == other->selectionMode()) &&
00102             (showDropIndicator()     == other->showDropIndicator()) &&
00103             (tabKeyNavigation()      == other->tabKeyNavigation()) &&
00104             (textElideMode()         == other->textElideMode()) &&
00105             // compare all of the properties stored in the attributes model
00106             attributesModel()->compare( other->attributesModel() ) &&
00107             // compare own properties
00108             (rootIndex().column()             == other->rootIndex().column()) &&
00109             (rootIndex().row()                == other->rootIndex().row()) &&
00110             (allowOverlappingDataValueTexts() == other->allowOverlappingDataValueTexts()) &&
00111             (antiAliasing()                   == other->antiAliasing()) &&
00112             (percentMode()                    == other->percentMode()) &&
00113             (datasetDimension()               == other->datasetDimension());
00114 }
00115 
00116 AbstractCoordinatePlane* AbstractDiagram::coordinatePlane() const
00117 {
00118     return d->plane;
00119 }
00120 
00121 const QPair<QPointF, QPointF> AbstractDiagram::dataBoundaries () const
00122 {
00123     if( d->databoundariesDirty ){
00124         d->databoundaries = calculateDataBoundaries ();
00125         d->databoundariesDirty = false;
00126     }
00127     return d->databoundaries;
00128 }
00129 
00130 void AbstractDiagram::setDataBoundariesDirty() const
00131 {
00132     d->databoundariesDirty = true;
00133     update();
00134 }
00135 
00136 void AbstractDiagram::setModel( QAbstractItemModel * newModel )
00137 {
00138     if( model() )
00139     {
00140         disconnect( model(), SIGNAL( rowsInserted( QModelIndex, int, int ) ), this, SLOT( setDataBoundariesDirty() ) );
00141         disconnect( model(), SIGNAL( columnsInserted( QModelIndex, int, int ) ), this, SLOT( setDataBoundariesDirty() ) );
00142         disconnect( model(), SIGNAL( rowsRemoved( QModelIndex, int, int ) ), this, SLOT( setDataBoundariesDirty() ) );
00143         disconnect( model(), SIGNAL( columnsRemoved( QModelIndex, int, int ) ), this, SLOT( setDataBoundariesDirty() ) );
00144         disconnect( model(), SIGNAL( modelReset() ), this, SLOT( setDataBoundariesDirty() ) );
00145         disconnect( model(), SIGNAL( layoutChanged() ), this, SLOT( setDataBoundariesDirty() ) );
00146         disconnect( model(), SIGNAL( dataChanged(QModelIndex,QModelIndex) ), this, SIGNAL( modelDataChanged() ));
00147     }
00148     QAbstractItemView::setModel( newModel );
00149     AttributesModel* amodel = new PrivateAttributesModel( newModel, this );
00150     amodel->initFrom( d->attributesModel );
00151     d->setAttributesModel(amodel);
00152     scheduleDelayedItemsLayout();
00153     setDataBoundariesDirty();
00154     if( model() )
00155     {
00156         connect( model(), SIGNAL( rowsInserted( QModelIndex, int, int ) ), this, SLOT( setDataBoundariesDirty() ) );
00157         connect( model(), SIGNAL( columnsInserted( QModelIndex, int, int ) ), this, SLOT( setDataBoundariesDirty() ) );
00158         connect( model(), SIGNAL( rowsRemoved( QModelIndex, int, int ) ), this, SLOT( setDataBoundariesDirty() ) );
00159         connect( model(), SIGNAL( columnsRemoved( QModelIndex, int, int ) ), this, SLOT( setDataBoundariesDirty() ) );
00160         connect( model(), SIGNAL( modelReset() ), this, SLOT( setDataBoundariesDirty() ) );
00161         connect( model(), SIGNAL( layoutChanged() ), this, SLOT( setDataBoundariesDirty() ) );
00162         connect( model(), SIGNAL( dataChanged(QModelIndex,QModelIndex) ), this, SIGNAL( modelDataChanged() ));
00163     }
00164     emit modelsChanged();
00165 }
00166 
00167 void AbstractDiagram::setSelectionModel( QItemSelectionModel* newSelectionModel )
00168 {
00169     if( selectionModel() )
00170     {
00171         disconnect( selectionModel(), SIGNAL( currentChanged( QModelIndex, QModelIndex ) ), this, SIGNAL( modelsChanged() ) );
00172         disconnect( selectionModel(), SIGNAL( selectionChanged( QItemSelection, QItemSelection ) ), this, SIGNAL( modelsChanged() ) );
00173     }
00174     QAbstractItemView::setSelectionModel( newSelectionModel );
00175     if( selectionModel() )
00176     {
00177         connect( selectionModel(), SIGNAL( currentChanged( QModelIndex, QModelIndex ) ), this, SIGNAL( modelsChanged() ) );
00178         connect( selectionModel(), SIGNAL( selectionChanged( QItemSelection, QItemSelection ) ), this, SIGNAL( modelsChanged() ) );
00179     }
00180     emit modelsChanged();
00181 }
00182 
00188 void AbstractDiagram::setAttributesModel( AttributesModel* amodel )
00189 {
00190     if( amodel->sourceModel() != model() ) {
00191         qWarning("KDChart::AbstractDiagram::setAttributesModel() failed: "
00192                  "Trying to set an attributesmodel which works on a different "
00193                  "model than the diagram.");
00194         return;
00195     }
00196     if( qobject_cast<PrivateAttributesModel*>(amodel) ) {
00197         qWarning("KDChart::AbstractDiagram::setAttributesModel() failed: "
00198                  "Trying to set an attributesmodel that is private to another diagram.");
00199         return;
00200     }
00201     d->setAttributesModel(amodel);
00202     scheduleDelayedItemsLayout();
00203     setDataBoundariesDirty();
00204     emit modelsChanged();
00205 }
00206 
00207 bool AbstractDiagram::usesExternalAttributesModel() const
00208 {
00209     return d->usesExternalAttributesModel();
00210 }
00211 
00212 AttributesModel* AbstractDiagram::attributesModel() const
00213 {
00214     return d->attributesModel;
00215 }
00216 
00217 QModelIndex AbstractDiagram::conditionallyMapFromSource( const QModelIndex & index ) const
00218 {
00219     Q_ASSERT( !index.isValid() || index.model() == attributesModel() || index.model() == attributesModel()->sourceModel() );
00220     return index.model() == attributesModel() ? index : attributesModel()->mapFromSource( index );
00221 }
00222 
00224 void AbstractDiagram::setRootIndex ( const QModelIndex& idx )
00225 {
00226     QAbstractItemView::setRootIndex( idx );
00227     setAttributesModelRootIndex( d->attributesModel->mapFromSource( idx ) );
00228 }
00229 
00231 void AbstractDiagram::setAttributesModelRootIndex( const QModelIndex& idx )
00232 {
00233     d->attributesModelRootIndex = idx;
00234     setDataBoundariesDirty();
00235     scheduleDelayedItemsLayout();
00236 }
00237 
00240 QModelIndex AbstractDiagram::attributesModelRootIndex() const
00241 {
00242     if ( !d->attributesModelRootIndex.isValid() )
00243         d->attributesModelRootIndex = d->attributesModel->mapFromSource( rootIndex() );
00244     return d->attributesModelRootIndex;
00245 }
00246 
00247 void AbstractDiagram::setCoordinatePlane( AbstractCoordinatePlane* parent )
00248 {
00249     d->plane = parent;
00250 }
00251 
00252 void AbstractDiagram::doItemsLayout()
00253 {
00254     if ( d->plane ) {
00255         d->plane->layoutDiagrams();
00256         update();
00257     }
00258     QAbstractItemView::doItemsLayout();
00259 }
00260 
00261 void AbstractDiagram::dataChanged( const QModelIndex &topLeft,
00262                                    const QModelIndex &bottomRight )
00263 {
00264     Q_UNUSED( topLeft );
00265     Q_UNUSED( bottomRight );
00266     // We are still too dumb to do intelligent updates...
00267     setDataBoundariesDirty();
00268     scheduleDelayedItemsLayout();
00269 }
00270 
00271 
00272 void AbstractDiagram::setHidden( const QModelIndex & index, bool hidden )
00273 {
00274     d->attributesModel->setData(
00275         conditionallyMapFromSource( index ),
00276         qVariantFromValue( hidden ),
00277         DataHiddenRole );
00278     emit dataHidden();
00279 }
00280 
00281 void AbstractDiagram::setHidden( int dataset, bool hidden )
00282 {
00283     d->setDatasetAttrs( dataset, qVariantFromValue( hidden ), DataHiddenRole );
00284     emit dataHidden();
00285 }
00286 
00287 void AbstractDiagram::setHidden( bool hidden )
00288 {
00289     d->attributesModel->setModelData( qVariantFromValue( hidden ), DataHiddenRole );
00290     emit dataHidden();
00291 }
00292 
00293 bool AbstractDiagram::isHidden() const
00294 {
00295     return qVariantValue< bool >( attributesModel()->modelData( DataHiddenRole ) );
00296 }
00297 
00298 bool AbstractDiagram::isHidden( int dataset ) const
00299 {
00300     const QVariant boolFlag( d->datasetAttrs( dataset, DataHiddenRole ) );
00301     if( boolFlag.isValid() )
00302         return qVariantValue< bool >( boolFlag );
00303     return isHidden();
00304 }
00305 
00306 bool AbstractDiagram::isHidden( const QModelIndex & index ) const
00307 {
00308     const QVariant boolFlag( attributesModel()->data( conditionallyMapFromSource( index ),
00309                                                       DataHiddenRole ) );
00310     if ( boolFlag.isValid() ) {
00311         return qVariantValue< bool >( boolFlag );
00312     }
00313     int dataset = index.column() / d->datasetDimension;
00314     return isHidden( dataset );
00315 }
00316 
00317 
00318 void AbstractDiagram::setDataValueAttributes( const QModelIndex & index,
00319                                               const DataValueAttributes & a )
00320 {
00321     d->attributesModel->setData( conditionallyMapFromSource( index ), qVariantFromValue( a ),
00322                                  DataValueLabelAttributesRole );
00323     emit propertiesChanged();
00324 }
00325 
00326 
00327 void AbstractDiagram::setDataValueAttributes( int dataset, const DataValueAttributes & a )
00328 {
00329     d->setDatasetAttrs( dataset, qVariantFromValue( a ), DataValueLabelAttributesRole );
00330     emit propertiesChanged();
00331 }
00332 
00333 DataValueAttributes AbstractDiagram::dataValueAttributes() const
00334 {
00335     return qVariantValue<DataValueAttributes>(
00336         attributesModel()->modelData( KDChart::DataValueLabelAttributesRole ) );
00337 }
00338 
00339 DataValueAttributes AbstractDiagram::dataValueAttributes( int dataset ) const
00340 {
00341     /*
00342     The following did not work!
00343     (khz, 2008-01-25)
00344     If there was some attrs specified for the 0-th cells of a dataset,
00345     then this logic would return the cell's settings instead of the header settings:
00346 
00347     return qVariantValue<DataValueAttributes>(
00348         attributesModel()->data( attributesModel()->mapFromSource(columnToIndex( column )),
00349         KDChart::DataValueLabelAttributesRole ) );
00350     */
00351 
00352     const QVariant headerAttrs(
00353         d->datasetAttrs( dataset, KDChart::DataValueLabelAttributesRole ) );
00354     if( headerAttrs.isValid() )
00355         return qVariantValue< DataValueAttributes >( headerAttrs );
00356     return dataValueAttributes();
00357 }
00358 
00359 DataValueAttributes AbstractDiagram::dataValueAttributes( const QModelIndex & index ) const
00360 {
00361     return qVariantValue<DataValueAttributes>(
00362         attributesModel()->data(
00363             conditionallyMapFromSource( index ),
00364             KDChart::DataValueLabelAttributesRole ) );
00365 }
00366 
00367 void AbstractDiagram::setDataValueAttributes( const DataValueAttributes & a )
00368 {
00369     d->attributesModel->setModelData( qVariantFromValue( a ), DataValueLabelAttributesRole );
00370     emit propertiesChanged();
00371 }
00372 
00373 void AbstractDiagram::setAllowOverlappingDataValueTexts( bool allow )
00374 {
00375     DataValueAttributes attrs = dataValueAttributes();
00376     attrs.setShowOverlappingDataLabels( allow );
00377     setDataValueAttributes( attrs );
00378     d->allowOverlappingDataValueTexts = allow;
00379     emit propertiesChanged();
00380 }
00381 
00382 bool AbstractDiagram::allowOverlappingDataValueTexts() const
00383 {
00384     return d->allowOverlappingDataValueTexts;
00385 }
00386 
00387 void AbstractDiagram::setAntiAliasing( bool enabled )
00388 {
00389     d->antiAliasing = enabled;
00390     emit propertiesChanged();
00391 }
00392 
00393 bool AbstractDiagram::antiAliasing() const
00394 {
00395     return d->antiAliasing;
00396 }
00397 
00398 void AbstractDiagram::setPercentMode ( bool percent )
00399 {
00400     d->percent = percent;
00401     emit propertiesChanged();
00402 }
00403 
00404 bool AbstractDiagram::percentMode() const
00405 {
00406     return d->percent;
00407 }
00408 
00409 
00410 void AbstractDiagram::paintDataValueText( QPainter* painter,
00411                                           const QModelIndex& index,
00412                                           const QPointF& pos,
00413                                           qreal value )
00414 {
00415     d->paintDataValueText( painter, index, pos, value );
00416 }
00417 
00418 
00419 void AbstractDiagram::paintDataValueTexts( QPainter* painter )
00420 {
00421     if ( !checkInvariants() ) {
00422         return;
00423     }
00424 
00425     d->forgetAlreadyPaintedDataValues();
00426     const int rowCount = model()->rowCount( rootIndex() );
00427     const int columnCount = model()->columnCount( rootIndex() );
00428     for ( int column = 0; column < columnCount; column += datasetDimension() ) {
00429         for ( int row = 0; row < rowCount; ++row ) {
00430             QModelIndex index = model()->index( row, column, rootIndex() ); // checked
00431             qreal x;
00432             qreal y;
00433             if ( datasetDimension() == 1 ) {
00434                 x = row;
00435                 y = index.data().toReal();
00436             } else {
00437                 x = index.data().toReal();
00438                 y = model()->index( row, column + 1, rootIndex() ).data().toReal();
00439             }
00440             paintDataValueText( painter, index, coordinatePlane()->translate( QPointF( x, y ) ), y );
00441         }
00442     }
00443 }
00444 
00445 
00446 void AbstractDiagram::paintMarker( QPainter* painter,
00447                                    const DataValueAttributes& a,
00448                                    const QModelIndex& index,
00449                                    const QPointF& pos )
00450 {
00451     if ( !checkInvariants() || !a.isVisible() ) return;
00452     const MarkerAttributes ma = a.markerAttributes();
00453     if ( !ma.isVisible() ) return;
00454 
00455     const PainterSaver painterSaver( painter );
00456     // the size of the marker - unscaled
00457     const QSizeF maSize( ma.markerSize().width() / painter->matrix().m11(),
00458                          ma.markerSize().height() / painter->matrix().m22() );
00459     QBrush indexBrush( brush( index ) );
00460     QPen indexPen( ma.pen() );
00461     if ( ma.markerColor().isValid() )
00462         indexBrush.setColor( ma.markerColor() );
00463 
00464     paintMarker( painter, ma, indexBrush, indexPen, pos, maSize );
00465 
00466     // workaround: BC cannot be changed, otherwise we would pass the
00467     // index down to next-lower paintMarker function. So far, we
00468     // basically save a circle of radius maSize at pos in the
00469     // reverseMapper. This means that ^^^ this version of paintMarker
00470     // needs to be called to reverse-map the marker.
00471     d->reverseMapper.addCircle( index.row(), index.column(), pos, 2 * maSize );
00472 }
00473 
00474 void AbstractDiagram::paintMarker( QPainter* painter,
00475                                    const QModelIndex& index,
00476                                    const QPointF& pos )
00477 {
00478     if ( !checkInvariants() ) return;
00479     paintMarker( painter, dataValueAttributes( index ), index, pos );
00480 }
00481 
00482 void AbstractDiagram::paintMarker( QPainter* painter,
00483                                    const MarkerAttributes& markerAttributes,
00484                                    const QBrush& brush,
00485                                    const QPen& pen,
00486                                    const QPointF& pos,
00487                                    const QSizeF& maSize )
00488 {
00489     const QPen oldPen( painter->pen() );
00490     // Pen is used to paint 4Pixels - 1 Pixel - Ring and FastCross types.
00491     // make sure to use the brush color - see above in those cases.
00492     const bool isFourPixels = (markerAttributes.markerStyle() == MarkerAttributes::Marker4Pixels);
00493     if( isFourPixels || (markerAttributes.markerStyle() == MarkerAttributes::Marker1Pixel) ){
00494         // for high-performance point charts with tiny point markers:
00495         painter->setPen( PrintingParameters::scalePen( QPen( brush.color().light() ) ) );
00496         if( isFourPixels ){
00497             const qreal x = pos.x();
00498             const qreal y = pos.y();
00499             painter->drawLine( QPointF(x-1.0,y-1.0),
00500                                QPointF(x+1.0,y-1.0) );
00501             painter->drawLine( QPointF(x-1.0,y),
00502                                QPointF(x+1.0,y) );
00503             painter->drawLine( QPointF(x-1.0,y+1.0),
00504                                QPointF(x+1.0,y+1.0) );
00505         }
00506         painter->drawPoint( pos );
00507     }else{
00508         const PainterSaver painterSaver( painter );
00509         QPen painterPen( pen );
00510         painter->setPen( PrintingParameters::scalePen( painterPen ) );
00511         painter->setBrush( brush );
00512         painter->setRenderHint ( QPainter::Antialiasing );
00513         painter->translate( pos );
00514         switch ( markerAttributes.markerStyle() ) {
00515             case MarkerAttributes::MarkerCircle:
00516             {
00517                 if ( markerAttributes.threeD() ) {
00518                     QRadialGradient grad;
00519                     grad.setCoordinateMode( QGradient::ObjectBoundingMode );
00520                     QColor drawColor = brush.color();
00521                     grad.setCenter( 0.5, 0.5 );
00522                     grad.setRadius( 1.0 );
00523                     grad.setFocalPoint( 0.35, 0.35 );
00524                     grad.setColorAt( 0.00, drawColor.lighter( 150 ) );
00525                     grad.setColorAt( 0.20, drawColor );
00526                     grad.setColorAt( 0.50, drawColor.darker( 150 ) );
00527                     grad.setColorAt( 0.75, drawColor.darker( 200 ) );
00528                     grad.setColorAt( 0.95, drawColor.darker( 250 ) );
00529                     grad.setColorAt( 1.00, drawColor.darker( 200 ) );
00530                     QBrush newBrush( grad );
00531                     newBrush.setMatrix( brush.matrix() );
00532                     painter->setBrush( newBrush );
00533                 }
00534                 painter->drawEllipse( QRectF( 0 - maSize.height()/2, 0 - maSize.width()/2,
00535                             maSize.height(), maSize.width()) );
00536             }
00537                 break;
00538             case MarkerAttributes::MarkerSquare:
00539                 {
00540                     QRectF rect( 0 - maSize.width()/2, 0 - maSize.height()/2,
00541                                 maSize.width(), maSize.height() );
00542                     painter->drawRect( rect );
00543                     break;
00544                 }
00545             case MarkerAttributes::MarkerDiamond:
00546                 {
00547                     QVector <QPointF > diamondPoints;
00548                     QPointF top, left, bottom, right;
00549                     top    = QPointF( 0, 0 - maSize.height()/2 );
00550                     left   = QPointF( 0 - maSize.width()/2, 0 );
00551                     bottom = QPointF( 0, maSize.height()/2 );
00552                     right  = QPointF( maSize.width()/2, 0 );
00553                     diamondPoints << top << left << bottom << right;
00554                     painter->drawPolygon( diamondPoints );
00555                     break;
00556                 }
00557             // both handled on top of the method:
00558             case MarkerAttributes::Marker1Pixel:
00559             case MarkerAttributes::Marker4Pixels:
00560                     break;
00561             case MarkerAttributes::MarkerRing:
00562                 {
00563                     painter->setBrush( Qt::NoBrush );
00564                     painter->drawEllipse( QRectF( 0 - maSize.height()/2, 0 - maSize.width()/2,
00565                                         maSize.height(), maSize.width()) );
00566                     break;
00567                 }
00568             case MarkerAttributes::MarkerCross:
00569                 {
00570                     // Note: Markers can have outline,
00571                     //       so just drawing two rects is NOT the solution here!
00572                     const qreal w02 = maSize.width() * 0.2;
00573                     const qreal w05 = maSize.width() * 0.5;
00574                     const qreal h02 = maSize.height()* 0.2;
00575                     const qreal h05 = maSize.height()* 0.5;
00576                     QVector <QPointF > crossPoints;
00577                     QPointF p[12];
00578                     p[ 0] = QPointF( -w02, -h05 );
00579                     p[ 1] = QPointF( w02, -h05 );
00580                     p[ 2] = QPointF( w02, -h02 );
00581                     p[ 3] = QPointF( w05, -h02 );
00582                     p[ 4] = QPointF( w05,  h02 );
00583                     p[ 5] = QPointF( w02,  h02 );
00584                     p[ 6] = QPointF( w02,  h05 );
00585                     p[ 7] = QPointF( -w02,  h05 );
00586                     p[ 8] = QPointF( -w02,  h02 );
00587                     p[ 9] = QPointF( -w05,  h02 );
00588                     p[10] = QPointF( -w05, -h02 );
00589                     p[11] = QPointF( -w02, -h02 );
00590                     for( int i=0; i<12; ++i )
00591                         crossPoints << p[i];
00592                     crossPoints << p[0];
00593                     painter->drawPolygon( crossPoints );
00594                     break;
00595                 }
00596             case MarkerAttributes::MarkerFastCross:
00597                 {
00598                     QPointF left, right, top, bottom;
00599                     left  = QPointF( -maSize.width()/2, 0 );
00600                     right = QPointF( maSize.width()/2, 0 );
00601                     top   = QPointF( 0, -maSize.height()/2 );
00602                     bottom= QPointF( 0, maSize.height()/2 );
00603                     painter->setPen( PrintingParameters::scalePen( QPen( brush.color() ) ) );
00604                     painter->drawLine( left, right );
00605                     painter->drawLine( top, bottom );
00606                     break;
00607                 }
00608             case MarkerAttributes::NoMarker:
00609                 break;
00610             case MarkerAttributes::PainterPathMarker:
00611                 {
00612                     QPainterPath path = markerAttributes.customMarkerPath();
00613                     painter->scale(maSize.height()/path.boundingRect().height(),
00614                                    maSize.width()/path.boundingRect().width());
00615                     painter->setPen( PrintingParameters::scalePen( QPen( brush.color() ) ) );
00616                     painter->drawPath(path);
00617                     break;
00618                 }
00619             default:
00620                 Q_ASSERT_X ( false, "paintMarkers()",
00621                             "Type item does not match a defined Marker Type." );
00622         }
00623     }
00624     painter->setPen( oldPen );
00625 }
00626 
00627 void AbstractDiagram::paintMarkers( QPainter* painter )
00628 {
00629     if ( !checkInvariants() ) {
00630         return;
00631     }
00632 
00633     const int rowCount = model()->rowCount( rootIndex() );
00634     const int columnCount = model()->columnCount( rootIndex() );
00635     for ( int column = 0; column < columnCount; column += datasetDimension() ) {
00636         for ( int row = 0; row < rowCount; ++row ) {
00637             QModelIndex index = model()->index( row, column, rootIndex() ); // checked
00638             qreal x;
00639             qreal y;
00640             if ( datasetDimension() == 1 ) {
00641                 x = row;
00642                 y = index.data().toReal();
00643             } else {
00644                 x = index.data().toReal();
00645                 y = model()->index( row, column + 1, rootIndex() ).data().toReal();
00646             }
00647             paintMarker( painter, index, coordinatePlane()->translate( QPointF( x, y ) ) );
00648         }
00649     }
00650 }
00651 
00652 
00653 void AbstractDiagram::setPen( const QModelIndex& index, const QPen& pen )
00654 {
00655     attributesModel()->setData(
00656         conditionallyMapFromSource( index ),
00657         qVariantFromValue( pen ), DatasetPenRole );
00658     emit propertiesChanged();
00659 }
00660 
00661 void AbstractDiagram::setPen( const QPen& pen )
00662 {
00663     attributesModel()->setModelData(
00664         qVariantFromValue( pen ), DatasetPenRole );
00665     emit propertiesChanged();
00666 }
00667 
00668 void AbstractDiagram::setPen( int dataset, const QPen& pen )
00669 {
00670     d->setDatasetAttrs( dataset, qVariantFromValue( pen ), DatasetPenRole );
00671     emit propertiesChanged();
00672 }
00673 
00674 QPen AbstractDiagram::pen() const
00675 {
00676     return qVariantValue<QPen>(
00677         attributesModel()->data( DatasetPenRole ) );
00678 }
00679 
00680 QPen AbstractDiagram::pen( int dataset ) const
00681 {
00682     const QVariant penSettings( d->datasetAttrs( dataset, DatasetPenRole ) );
00683     if( penSettings.isValid() )
00684         return qVariantValue< QPen >( penSettings );
00685     return pen();
00686 }
00687 
00688 QPen AbstractDiagram::pen( const QModelIndex& index ) const
00689 {
00690     return qVariantValue<QPen>(
00691         attributesModel()->data(
00692             conditionallyMapFromSource( index ),
00693             DatasetPenRole ) );
00694 }
00695 
00696 void AbstractDiagram::setBrush( const QModelIndex& index, const QBrush& brush )
00697 {
00698     attributesModel()->setData(
00699         conditionallyMapFromSource( index ),
00700         qVariantFromValue( brush ), DatasetBrushRole );
00701     emit propertiesChanged();
00702 }
00703 
00704 void AbstractDiagram::setBrush( const QBrush& brush )
00705 {
00706     attributesModel()->setModelData(
00707         qVariantFromValue( brush ), DatasetBrushRole );
00708     emit propertiesChanged();
00709 }
00710 
00711 void AbstractDiagram::setBrush( int dataset, const QBrush& brush )
00712 {
00713     d->setDatasetAttrs( dataset, qVariantFromValue( brush ), DatasetBrushRole );
00714     emit propertiesChanged();
00715 }
00716 
00717 QBrush AbstractDiagram::brush() const
00718 {
00719     return qVariantValue<QBrush>(
00720         attributesModel()->data( DatasetBrushRole ) );
00721 }
00722 
00723 QBrush AbstractDiagram::brush( int dataset ) const
00724 {
00725     const QVariant brushSettings( d->datasetAttrs( dataset, DatasetBrushRole ) );
00726     if( brushSettings.isValid() )
00727         return qVariantValue< QBrush >( brushSettings );
00728     return brush();
00729 }
00730 
00731 QBrush AbstractDiagram::brush( const QModelIndex& index ) const
00732 {
00733     return qVariantValue<QBrush>(
00734         attributesModel()->data( conditionallyMapFromSource( index ), DatasetBrushRole ) );
00735 }
00736 
00743 void AbstractDiagram::setUnitPrefix( const QString& prefix, int column, Qt::Orientation orientation )
00744 {
00745     d->unitPrefixMap[ column ][ orientation ]= prefix;
00746 }
00747 
00753 void AbstractDiagram::setUnitPrefix( const QString& prefix, Qt::Orientation orientation )
00754 {
00755     d->unitPrefix[ orientation ] = prefix;
00756 }
00757 
00764 void AbstractDiagram::setUnitSuffix( const QString& suffix, int column, Qt::Orientation orientation )
00765 {
00766     d->unitSuffixMap[ column ][ orientation ]= suffix;
00767 }
00768 
00774 void AbstractDiagram::setUnitSuffix( const QString& suffix, Qt::Orientation orientation )
00775 {
00776     d->unitSuffix[ orientation ] = suffix;
00777 }
00778 
00786 QString AbstractDiagram::unitPrefix( int column, Qt::Orientation orientation, bool fallback ) const
00787 {
00788     if( !fallback || d->unitPrefixMap[ column ].contains( orientation ) )
00789         return d->unitPrefixMap[ column ][ orientation ];
00790     return d->unitPrefix[ orientation ];
00791 }
00792 
00797 QString AbstractDiagram::unitPrefix( Qt::Orientation orientation ) const
00798 {
00799     return d->unitPrefix[ orientation ];
00800 }
00801 
00809 QString AbstractDiagram::unitSuffix( int column, Qt::Orientation orientation, bool fallback ) const
00810 {
00811     if( !fallback || d->unitSuffixMap[ column ].contains( orientation ) )
00812         return d->unitSuffixMap[ column ][ orientation ];
00813     return d->unitSuffix[ orientation ];
00814 }
00815 
00820 QString AbstractDiagram::unitSuffix( Qt::Orientation orientation ) const
00821 {
00822     return d->unitSuffix[ orientation ];
00823 }
00824 
00825 // implement QAbstractItemView:
00826 QRect AbstractDiagram::visualRect( const QModelIndex &index ) const
00827 {
00828     return d->reverseMapper.boundingRect( index.row(), index.column() ).toRect();
00829 }
00830 
00831 void AbstractDiagram::scrollTo(const QModelIndex &, ScrollHint )
00832 {}
00833 
00834 // indexAt ... down below
00835 
00836 QModelIndex AbstractDiagram::moveCursor(CursorAction, Qt::KeyboardModifiers )
00837 { return QModelIndex(); }
00838 
00839 int AbstractDiagram::horizontalOffset() const
00840 { return 0; }
00841 
00842 int AbstractDiagram::verticalOffset() const
00843 { return 0; }
00844 
00845 bool AbstractDiagram::isIndexHidden(const QModelIndex &) const
00846 { return true; }
00847 
00848 void AbstractDiagram::setSelection(const QRect& rect , QItemSelectionModel::SelectionFlags command )
00849 {
00850     const QModelIndexList indexes = d->indexesIn( rect );
00851     QItemSelection selection;
00852     KDAB_FOREACH( const QModelIndex& index, indexes )
00853     {
00854         selection.append( QItemSelectionRange( index ) );
00855     }
00856     selectionModel()->select( selection, command );
00857 }
00858 
00859 QRegion AbstractDiagram::visualRegionForSelection(const QItemSelection &selection) const
00860 {
00861     QPolygonF polygon;
00862     KDAB_FOREACH( const QModelIndex& index, selection.indexes() )
00863     {
00864         polygon << d->reverseMapper.polygon(index.row(), index.column());
00865     }
00866     return polygon.isEmpty() ? QRegion() : QRegion( polygon.toPolygon() );
00867 }
00868 
00869 QRegion AbstractDiagram::visualRegion(const QModelIndex &index) const
00870 {
00871     QPolygonF polygon = d->reverseMapper.polygon(index.row(), index.column());
00872     return polygon.isEmpty() ? QRegion() : QRegion( polygon.toPolygon() );
00873 }
00874 
00875 void KDChart::AbstractDiagram::useDefaultColors( )
00876 {
00877     d->attributesModel->setPaletteType( AttributesModel::PaletteTypeDefault );
00878 }
00879 
00880 void KDChart::AbstractDiagram::useSubduedColors( )
00881 {
00882     d->attributesModel->setPaletteType( AttributesModel::PaletteTypeSubdued );
00883 }
00884 
00885 void KDChart::AbstractDiagram::useRainbowColors( )
00886 {
00887     d->attributesModel->setPaletteType( AttributesModel::PaletteTypeRainbow );
00888 }
00889 
00890 QStringList AbstractDiagram::itemRowLabels() const
00891 {
00892     QStringList ret;
00893     if( model() ){
00894         //qDebug() << "AbstractDiagram::itemRowLabels(): " << attributesModel()->rowCount(attributesModelRootIndex()) << "entries";
00895         const int rowCount = attributesModel()->rowCount(attributesModelRootIndex());
00896         for( int i = 0; i < rowCount; ++i ){
00897             //qDebug() << "item row label: " << attributesModel()->headerData( i, Qt::Vertical, Qt::DisplayRole ).toString();
00898             ret << unitPrefix( i, Qt::Horizontal, true ) +
00899                    attributesModel()->headerData( i, Qt::Vertical, Qt::DisplayRole ).toString() +
00900                    unitSuffix( i, Qt::Horizontal, true );
00901         }
00902     }
00903     return ret;
00904 }
00905 
00906 QStringList AbstractDiagram::datasetLabels() const
00907 {
00908     QStringList ret;
00909     if ( !model() ) {
00910         return ret;
00911     }
00912     const int datasetCount = d->datasetCount();
00913     for ( int i = 0; i < datasetCount; ++i ) {
00914         ret << d->datasetAttrs( i, Qt::DisplayRole ).toString();
00915     }
00916     return ret;
00917 }
00918 
00919 QList<QBrush> AbstractDiagram::datasetBrushes() const
00920 {
00921     QList<QBrush> ret;
00922     if ( !model() ) {
00923         return ret;
00924     }
00925     const int datasetCount = d->datasetCount();
00926     for ( int i = 0; i < datasetCount; ++i ) {
00927         ret << brush( i );
00928     }
00929     return ret;
00930 }
00931 
00932 QList<QPen> AbstractDiagram::datasetPens() const
00933 {
00934     QList<QPen> ret;
00935     if ( !model() ) {
00936         return ret;
00937     }
00938     const int datasetCount = d->datasetCount();
00939     for ( int i = 0; i < datasetCount; ++i ) {
00940         ret << pen( i );
00941     }
00942     return ret;
00943 }
00944 
00945 QList<MarkerAttributes> AbstractDiagram::datasetMarkers() const
00946 {
00947     QList<MarkerAttributes> ret;
00948     if ( !model() ) {
00949         return ret;
00950     }
00951     const int datasetCount = d->datasetCount();
00952     for ( int i = 0; i < datasetCount; ++i ) {
00953         ret << dataValueAttributes( i ).markerAttributes();
00954     }
00955     return ret;
00956 }
00957 
00958 bool AbstractDiagram::checkInvariants( bool justReturnTheStatus ) const
00959 {
00960     if( ! justReturnTheStatus ){
00961         Q_ASSERT_X ( model(), "AbstractDiagram::checkInvariants()",
00962                     "There is no usable model set, for the diagram." );
00963 
00964         Q_ASSERT_X ( coordinatePlane(), "AbstractDiagram::checkInvariants()",
00965                     "There is no usable coordinate plane set, for the diagram." );
00966     }
00967     return model() && coordinatePlane();
00968 }
00969 
00970 int AbstractDiagram::datasetDimension( ) const
00971 {
00972     return d->datasetDimension;
00973 }
00974 
00975 void AbstractDiagram::setDatasetDimension( int dimension )
00976 {
00977     Q_UNUSED( dimension );
00978     qDebug() << "Setting the dataset dimension using AbstractDiagram::setDatasetDimension is "
00979                 "obsolete. Use the specific diagram types instead.";
00980 }
00981 
00982 void AbstractDiagram::setDatasetDimensionInternal( int dimension )
00983 {
00984     Q_ASSERT( dimension != 0 );
00985     if ( d->datasetDimension == dimension ) {
00986         return;
00987     }
00988     d->datasetDimension = dimension;
00989     d->attributesModel->setDatasetDimension( dimension );
00990     setDataBoundariesDirty();
00991     emit layoutChanged( this );
00992 }
00993 
00994 qreal AbstractDiagram::valueForCell( int row, int column ) const
00995 {
00996     if ( !d->attributesModel->hasIndex( row, column, attributesModelRootIndex() ) ) {
00997         qWarning() << "AbstractDiagram::valueForCell(): Requesting value for invalid index!";
00998         return std::numeric_limits<qreal>::quiet_NaN();
00999     }
01000     return d->attributesModel->data(
01001             d->attributesModel->index( row, column, attributesModelRootIndex() ) ).toReal(); // checked
01002 }
01003 
01004 void AbstractDiagram::update() const
01005 {
01006     if ( d->plane ) {
01007         d->plane->update();
01008     }
01009 }
01010 
01011 QModelIndex AbstractDiagram::indexAt( const QPoint& point ) const
01012 {
01013     return d->indexAt( point );
01014 }
01015 
01016 QModelIndexList AbstractDiagram::indexesAt( const QPoint& point ) const
01017 {
01018     return d->indexesAt( point );
01019 }
01020 
01021 QModelIndexList AbstractDiagram::indexesIn( const QRect& rect ) const
01022 {
01023     return d->indexesIn( rect );
01024 }
 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/