File indexing completed on 2024-05-12 04:20:29
0001 /* 0002 * SPDX-FileCopyrightText: 2001-2015 Klaralvdalens Datakonsult AB. All rights reserved. 0003 * 0004 * This file is part of the KD Chart library. 0005 * 0006 * SPDX-License-Identifier: GPL-2.0-or-later 0007 */ 0008 0009 #include "KChartAbstractDiagram.h" 0010 #include "KChartAbstractDiagram_p.h" 0011 0012 #include <QPainter> 0013 #include <QPainterPath> 0014 #include <QDebug> 0015 #include <QApplication> 0016 #include <QAbstractProxyModel> 0017 #include <QSizeF> 0018 #include <QPainterPath> 0019 0020 #include "KChartAbstractCoordinatePlane.h" 0021 #include "KChartChart.h" 0022 #include "KChartDataValueAttributes.h" 0023 #include "KChartTextAttributes.h" 0024 #include "KChartAbstractThreeDAttributes.h" 0025 #include "KChartThreeDLineAttributes.h" 0026 #include "KChartPainterSaver_p.h" 0027 0028 #include <limits> 0029 0030 using namespace KChart; 0031 0032 #define d d_func() 0033 0034 AbstractDiagram::AbstractDiagram ( QWidget* parent, AbstractCoordinatePlane* plane ) 0035 : QAbstractItemView ( parent ), _d( new Private() ) 0036 { 0037 _d->init( plane ); 0038 init(); 0039 } 0040 0041 AbstractDiagram::~AbstractDiagram() 0042 { 0043 Q_EMIT aboutToBeDestroyed(); 0044 delete _d; 0045 } 0046 0047 void AbstractDiagram::init() 0048 { 0049 _d->diagram = this; 0050 d->reverseMapper.setDiagram( this ); 0051 } 0052 0053 0054 bool AbstractDiagram::compare( const AbstractDiagram* other ) const 0055 { 0056 if ( other == this ) return true; 0057 if ( !other ) { 0058 return false; 0059 } 0060 return // compare QAbstractScrollArea properties 0061 (horizontalScrollBarPolicy() == other->horizontalScrollBarPolicy()) && 0062 (verticalScrollBarPolicy() == other->verticalScrollBarPolicy()) && 0063 // compare QFrame properties 0064 (frameShadow() == other->frameShadow()) && 0065 (frameShape() == other->frameShape()) && 0066 // frameWidth is a read-only property defined by the style, it should not be in here: 0067 // (frameWidth() == other->frameWidth()) && 0068 (lineWidth() == other->lineWidth()) && 0069 (midLineWidth() == other->midLineWidth()) && 0070 // compare QAbstractItemView properties 0071 (alternatingRowColors() == other->alternatingRowColors()) && 0072 (hasAutoScroll() == other->hasAutoScroll()) && 0073 (dragDropMode() == other->dragDropMode()) && 0074 (dragDropOverwriteMode() == other->dragDropOverwriteMode()) && 0075 (horizontalScrollMode() == other->horizontalScrollMode ()) && 0076 (verticalScrollMode() == other->verticalScrollMode()) && 0077 (dragEnabled() == other->dragEnabled()) && 0078 (editTriggers() == other->editTriggers()) && 0079 (iconSize() == other->iconSize()) && 0080 (selectionBehavior() == other->selectionBehavior()) && 0081 (selectionMode() == other->selectionMode()) && 0082 (showDropIndicator() == other->showDropIndicator()) && 0083 (tabKeyNavigation() == other->tabKeyNavigation()) && 0084 (textElideMode() == other->textElideMode()) && 0085 // compare all of the properties stored in the attributes model 0086 attributesModel()->compare( other->attributesModel() ) && 0087 // compare own properties 0088 (rootIndex().column() == other->rootIndex().column()) && 0089 (rootIndex().row() == other->rootIndex().row()) && 0090 (allowOverlappingDataValueTexts() == other->allowOverlappingDataValueTexts()) && 0091 (antiAliasing() == other->antiAliasing()) && 0092 (percentMode() == other->percentMode()) && 0093 (datasetDimension() == other->datasetDimension()); 0094 } 0095 0096 AbstractCoordinatePlane* AbstractDiagram::coordinatePlane() const 0097 { 0098 return d->plane; 0099 } 0100 0101 const QPair<QPointF, QPointF> AbstractDiagram::dataBoundaries () const 0102 { 0103 if ( d->databoundariesDirty ) { 0104 d->databoundaries = calculateDataBoundaries (); 0105 d->databoundariesDirty = false; 0106 } 0107 return d->databoundaries; 0108 } 0109 0110 void AbstractDiagram::setDataBoundariesDirty() const 0111 { 0112 d->databoundariesDirty = true; 0113 update(); 0114 } 0115 0116 void AbstractDiagram::resize(const QSizeF& size) 0117 { 0118 d->diagramSize = size; 0119 QAbstractItemView::resize( size.toSize() ); 0120 } 0121 0122 void AbstractDiagram::setModel( QAbstractItemModel * newModel ) 0123 { 0124 if ( newModel == model() ) { 0125 return; 0126 } 0127 0128 AttributesModel* amodel = new PrivateAttributesModel( newModel, this ); 0129 amodel->initFrom( d->attributesModel ); 0130 d->setAttributesModel(amodel); 0131 0132 QAbstractItemView::setModel( newModel ); 0133 0134 scheduleDelayedItemsLayout(); 0135 setDataBoundariesDirty(); 0136 Q_EMIT modelsChanged(); 0137 } 0138 0139 void AbstractDiagram::setSelectionModel( QItemSelectionModel* newSelectionModel ) 0140 { 0141 if ( selectionModel() ) 0142 { 0143 disconnect( selectionModel(), SIGNAL(currentChanged(QModelIndex,QModelIndex)), this, SIGNAL(modelsChanged()) ); 0144 disconnect( selectionModel(), SIGNAL(selectionChanged(QItemSelection,QItemSelection)), this, SIGNAL(modelsChanged()) ); 0145 } 0146 QAbstractItemView::setSelectionModel( newSelectionModel ); 0147 if ( selectionModel() ) 0148 { 0149 connect( selectionModel(), SIGNAL(currentChanged(QModelIndex,QModelIndex)), this, SIGNAL(modelsChanged()) ); 0150 connect( selectionModel(), SIGNAL(selectionChanged(QItemSelection,QItemSelection)), this, SIGNAL(modelsChanged()) ); 0151 } 0152 Q_EMIT modelsChanged(); 0153 } 0154 0155 /* Sets an external AttributesModel on this diagram. By default, a diagram has it's 0156 own internal set of attributes, but an external one can be set. This can be used to 0157 share attributes between several diagrams. The diagram does not take ownership of the 0158 attributesmodel. 0159 0160 @param amodel The AttributesModel to use for this diagram. 0161 */ 0162 void AbstractDiagram::setAttributesModel( AttributesModel* amodel ) 0163 { 0164 if ( amodel->sourceModel() != model() ) { 0165 qWarning("KChart::AbstractDiagram::setAttributesModel() failed: " 0166 "Trying to set an attributesmodel which works on a different " 0167 "model than the diagram."); 0168 return; 0169 } 0170 if ( qobject_cast<PrivateAttributesModel*>(amodel) ) { 0171 qWarning("KChart::AbstractDiagram::setAttributesModel() failed: " 0172 "Trying to set an attributesmodel that is private to another diagram."); 0173 return; 0174 } 0175 0176 d->setAttributesModel( amodel ); 0177 scheduleDelayedItemsLayout(); 0178 setDataBoundariesDirty(); 0179 Q_EMIT modelsChanged(); 0180 } 0181 0182 bool AbstractDiagram::usesExternalAttributesModel() const 0183 { 0184 return d->usesExternalAttributesModel(); 0185 } 0186 0187 AttributesModel* AbstractDiagram::attributesModel() const 0188 { 0189 return d->attributesModel; 0190 } 0191 0192 QModelIndex AbstractDiagram::conditionallyMapFromSource( const QModelIndex & index ) const 0193 { 0194 Q_ASSERT( !index.isValid() || index.model() == attributesModel() || index.model() == attributesModel()->sourceModel() ); 0195 return index.model() == attributesModel() ? index : attributesModel()->mapFromSource( index ); 0196 } 0197 0198 /* \reimpl */ 0199 void AbstractDiagram::setRootIndex( const QModelIndex& idx ) 0200 { 0201 QAbstractItemView::setRootIndex( idx ); 0202 setAttributesModelRootIndex( d->attributesModel->mapFromSource( idx ) ); 0203 } 0204 0205 void AbstractDiagram::setAttributesModelRootIndex( const QModelIndex& idx ) 0206 { 0207 d->attributesModelRootIndex = idx; 0208 setDataBoundariesDirty(); 0209 scheduleDelayedItemsLayout(); 0210 } 0211 0212 QModelIndex AbstractDiagram::attributesModelRootIndex() const 0213 { 0214 if ( !d->attributesModelRootIndex.isValid() ) 0215 d->attributesModelRootIndex = d->attributesModel->mapFromSource( rootIndex() ); 0216 return d->attributesModelRootIndex; 0217 } 0218 0219 void AbstractDiagram::setCoordinatePlane( AbstractCoordinatePlane* parent ) 0220 { 0221 d->plane = parent; 0222 } 0223 0224 void AbstractDiagram::doItemsLayout() 0225 { 0226 if ( d->plane ) { 0227 d->plane->layoutDiagrams(); 0228 update(); 0229 } 0230 QAbstractItemView::doItemsLayout(); 0231 } 0232 0233 void AbstractDiagram::dataChanged( const QModelIndex &topLeft, 0234 const QModelIndex &bottomRight, 0235 const QVector<int> & ) 0236 { 0237 Q_UNUSED( topLeft ); 0238 Q_UNUSED( bottomRight ); 0239 // We are still too dumb to do intelligent updates... 0240 setDataBoundariesDirty(); 0241 scheduleDelayedItemsLayout(); 0242 } 0243 0244 0245 void AbstractDiagram::setHidden( const QModelIndex & index, bool hidden ) 0246 { 0247 d->attributesModel->setData( 0248 conditionallyMapFromSource( index ), 0249 QVariant::fromValue( hidden ), 0250 DataHiddenRole ); 0251 Q_EMIT dataHidden(); 0252 } 0253 0254 void AbstractDiagram::setHidden( int dataset, bool hidden ) 0255 { 0256 d->setDatasetAttrs( dataset, QVariant::fromValue( hidden ), DataHiddenRole ); 0257 Q_EMIT dataHidden(); 0258 } 0259 0260 void AbstractDiagram::setHidden( bool hidden ) 0261 { 0262 d->attributesModel->setModelData( QVariant::fromValue( hidden ), DataHiddenRole ); 0263 Q_EMIT dataHidden(); 0264 } 0265 0266 bool AbstractDiagram::isHidden() const 0267 { 0268 return attributesModel()->modelData( DataHiddenRole ).value< bool >(); 0269 } 0270 0271 bool AbstractDiagram::isHidden( int dataset ) const 0272 { 0273 const QVariant boolFlag( d->datasetAttrs( dataset, DataHiddenRole ) ); 0274 if ( boolFlag.isValid() ) 0275 return boolFlag.value< bool >(); 0276 return isHidden(); 0277 } 0278 0279 bool AbstractDiagram::isHidden( const QModelIndex & index ) const 0280 { 0281 const QVariant boolFlag( attributesModel()->data( conditionallyMapFromSource( index ), 0282 DataHiddenRole ) ); 0283 if ( boolFlag.isValid() ) { 0284 return boolFlag.value< bool >(); 0285 } 0286 int dataset = index.column() / d->datasetDimension; 0287 return isHidden( dataset ); 0288 } 0289 0290 0291 void AbstractDiagram::setDataValueAttributes( const QModelIndex & index, 0292 const DataValueAttributes & a ) 0293 { 0294 d->attributesModel->setData( conditionallyMapFromSource( index ), QVariant::fromValue( a ), 0295 DataValueLabelAttributesRole ); 0296 Q_EMIT propertiesChanged(); 0297 } 0298 0299 0300 void AbstractDiagram::setDataValueAttributes( int dataset, const DataValueAttributes & a ) 0301 { 0302 d->setDatasetAttrs( dataset, QVariant::fromValue( a ), DataValueLabelAttributesRole ); 0303 Q_EMIT propertiesChanged(); 0304 } 0305 0306 DataValueAttributes AbstractDiagram::dataValueAttributes() const 0307 { 0308 return attributesModel()->modelData( KChart::DataValueLabelAttributesRole ).value< DataValueAttributes >(); 0309 } 0310 0311 DataValueAttributes AbstractDiagram::dataValueAttributes( int dataset ) const 0312 { 0313 /* 0314 The following did not work! 0315 (khz, 2008-01-25) 0316 If there was some attrs specified for the 0-th cells of a dataset, 0317 then this logic would return the cell's settings instead of the header settings: 0318 0319 return qVariantValue<DataValueAttributes>( 0320 attributesModel()->data( attributesModel()->mapFromSource(columnToIndex( column )), 0321 KChart::DataValueLabelAttributesRole ) ); 0322 */ 0323 0324 const QVariant headerAttrs( 0325 d->datasetAttrs( dataset, KChart::DataValueLabelAttributesRole ) ); 0326 if ( headerAttrs.isValid() ) 0327 return headerAttrs.value< DataValueAttributes >(); 0328 return dataValueAttributes(); 0329 } 0330 0331 DataValueAttributes AbstractDiagram::dataValueAttributes( const QModelIndex & index ) const 0332 { 0333 return attributesModel()->data( 0334 conditionallyMapFromSource( index ), 0335 KChart::DataValueLabelAttributesRole ).value< DataValueAttributes >(); 0336 } 0337 0338 void AbstractDiagram::setDataValueAttributes( const DataValueAttributes & a ) 0339 { 0340 d->attributesModel->setModelData( QVariant::fromValue( a ), DataValueLabelAttributesRole ); 0341 Q_EMIT propertiesChanged(); 0342 } 0343 0344 void AbstractDiagram::setAllowOverlappingDataValueTexts( bool allow ) 0345 { 0346 DataValueAttributes attrs = dataValueAttributes(); 0347 attrs.setShowOverlappingDataLabels( allow ); 0348 setDataValueAttributes( attrs ); 0349 d->allowOverlappingDataValueTexts = allow; 0350 Q_EMIT propertiesChanged(); 0351 } 0352 0353 bool AbstractDiagram::allowOverlappingDataValueTexts() const 0354 { 0355 return d->allowOverlappingDataValueTexts; 0356 } 0357 0358 void AbstractDiagram::setAntiAliasing( bool enabled ) 0359 { 0360 d->antiAliasing = enabled; 0361 Q_EMIT propertiesChanged(); 0362 } 0363 0364 bool AbstractDiagram::antiAliasing() const 0365 { 0366 return d->antiAliasing; 0367 } 0368 0369 void AbstractDiagram::setPercentMode ( bool percent ) 0370 { 0371 d->percent = percent; 0372 Q_EMIT propertiesChanged(); 0373 } 0374 0375 bool AbstractDiagram::percentMode() const 0376 { 0377 return d->percent; 0378 } 0379 0380 0381 void AbstractDiagram::paintDataValueText( QPainter* painter, 0382 const QModelIndex& index, 0383 const QPointF& pos, 0384 qreal value ) 0385 { 0386 d->paintDataValueText( painter, index, pos, value ); 0387 } 0388 0389 0390 void AbstractDiagram::paintDataValueTexts( QPainter* painter ) 0391 { 0392 if ( !checkInvariants() ) { 0393 return; 0394 } 0395 0396 d->forgetAlreadyPaintedDataValues(); 0397 const int rowCount = model()->rowCount( rootIndex() ); 0398 const int columnCount = model()->columnCount( rootIndex() ); 0399 for ( int column = 0; column < columnCount; column += datasetDimension() ) { 0400 for ( int row = 0; row < rowCount; ++row ) { 0401 QModelIndex index = model()->index( row, column, rootIndex() ); // checked 0402 qreal x; 0403 qreal y; 0404 if ( datasetDimension() == 1 ) { 0405 x = row; 0406 y = index.data().toReal(); 0407 } else { 0408 x = index.data().toReal(); 0409 y = model()->index( row, column + 1, rootIndex() ).data().toReal(); 0410 } 0411 paintDataValueText( painter, index, coordinatePlane()->translate( QPointF( x, y ) ), y ); 0412 } 0413 } 0414 } 0415 0416 0417 void AbstractDiagram::paintMarker( QPainter* painter, 0418 const DataValueAttributes& a, 0419 const QModelIndex& index, 0420 const QPointF& pos ) 0421 { 0422 if ( !checkInvariants() || !a.isVisible() ) return; 0423 const MarkerAttributes ma = a.markerAttributes(); 0424 if ( !ma.isVisible() ) return; 0425 0426 const PainterSaver painterSaver( painter ); 0427 0428 QSizeF maSize = ma.markerSize(); 0429 const qreal diagramWidth = d->diagramSize.width(); 0430 const qreal diagramHeight = d->diagramSize.height(); 0431 0432 switch( ma.markerSizeMode() ) { 0433 case MarkerAttributes::AbsoluteSize: 0434 // Unscaled, i.e. without the painter's "zoom" 0435 maSize.rwidth() /= painter->transform().m11(); 0436 maSize.rheight() /= painter->transform().m22(); 0437 break; 0438 case MarkerAttributes::AbsoluteSizeScaled: 0439 // Keep maSize as is. It is specified directly in pixels and desired 0440 // to be effected by the painter's "zoom". 0441 break; 0442 case MarkerAttributes::RelativeToDiagramWidthHeightMin: 0443 maSize *= qMin( diagramWidth, diagramHeight ); 0444 break; 0445 } 0446 0447 QBrush indexBrush( brush( index ) ); 0448 QPen indexPen( ma.pen() ); 0449 if ( ma.markerColor().isValid() ) 0450 indexBrush.setColor( ma.markerColor() ); 0451 0452 paintMarker( painter, ma, indexBrush, indexPen, pos, maSize ); 0453 0454 // workaround: BC cannot be changed, otherwise we would pass the 0455 // index down to next-lower paintMarker function. So far, we 0456 // basically save a circle of radius maSize at pos in the 0457 // reverseMapper. This means that ^^^ this version of paintMarker 0458 // needs to be called to reverse-map the marker. 0459 if ((ma.markerStyle() == MarkerAttributes::Marker4Pixels) || (ma.markerStyle() == MarkerAttributes::Marker1Pixel)) { 0460 auto rect = QRectF({}, maSize); 0461 rect.moveCenter(pos); 0462 d->reverseMapper.addRect( index.row(), index.column(), rect ); 0463 } else { 0464 d->reverseMapper.addCircle( index.row(), index.column(), pos, 2 * maSize ); 0465 } 0466 } 0467 0468 void AbstractDiagram::paintMarker( QPainter* painter, 0469 const QModelIndex& index, 0470 const QPointF& pos ) 0471 { 0472 if ( !checkInvariants() ) return; 0473 paintMarker( painter, dataValueAttributes( index ), index, pos ); 0474 } 0475 0476 void AbstractDiagram::paintMarker( QPainter* painter, 0477 const MarkerAttributes& markerAttributes, 0478 const QBrush& brush, 0479 const QPen& pen, 0480 const QPointF& pos, 0481 const QSizeF& maSize ) 0482 { 0483 const QPen oldPen( painter->pen() ); 0484 // Pen is used to paint 4Pixels - 1 Pixel - Ring and FastCross types. 0485 // make sure to use the brush color - see above in those cases. 0486 const bool isFourPixels = (markerAttributes.markerStyle() == MarkerAttributes::Marker4Pixels); 0487 if ( isFourPixels || (markerAttributes.markerStyle() == MarkerAttributes::Marker1Pixel) ) { 0488 // for high-performance point charts with tiny point markers: 0489 painter->setPen( PrintingParameters::scalePen( QPen( brush.color().lighter() ) ) ); 0490 if ( isFourPixels ) { 0491 const qreal x = pos.x(); 0492 const qreal y = pos.y(); 0493 painter->drawLine( QPointF(x-1.0,y-1.0), 0494 QPointF(x+1.0,y-1.0) ); 0495 painter->drawLine( QPointF(x-1.0,y), 0496 QPointF(x+1.0,y) ); 0497 painter->drawLine( QPointF(x-1.0,y+1.0), 0498 QPointF(x+1.0,y+1.0) ); 0499 } 0500 painter->drawPoint( pos ); 0501 } else { 0502 const PainterSaver painterSaver( painter ); 0503 QPen painterPen( pen ); 0504 painter->setPen( PrintingParameters::scalePen( painterPen ) ); 0505 painter->setBrush( brush ); 0506 painter->setRenderHint ( QPainter::Antialiasing ); 0507 painter->translate( pos ); 0508 switch ( markerAttributes.markerStyle() ) { 0509 case MarkerAttributes::MarkerCircle: 0510 { 0511 if ( markerAttributes.threeD() ) { 0512 QRadialGradient grad; 0513 grad.setCoordinateMode( QGradient::ObjectBoundingMode ); 0514 QColor drawColor = brush.color(); 0515 grad.setCenter( 0.5, 0.5 ); 0516 grad.setRadius( 1.0 ); 0517 grad.setFocalPoint( 0.35, 0.35 ); 0518 grad.setColorAt( 0.00, drawColor.lighter( 150 ) ); 0519 grad.setColorAt( 0.20, drawColor ); 0520 grad.setColorAt( 0.50, drawColor.darker( 150 ) ); 0521 grad.setColorAt( 0.75, drawColor.darker( 200 ) ); 0522 grad.setColorAt( 0.95, drawColor.darker( 250 ) ); 0523 grad.setColorAt( 1.00, drawColor.darker( 200 ) ); 0524 QBrush newBrush( grad ); 0525 newBrush.setTransform( brush.transform() ); 0526 painter->setBrush( newBrush ); 0527 } 0528 painter->drawEllipse( QRectF( 0 - maSize.height()/2, 0 - maSize.width()/2, 0529 maSize.height(), maSize.width()) ); 0530 } 0531 break; 0532 case MarkerAttributes::MarkerSquare: 0533 { 0534 QRectF rect( 0 - maSize.width()/2, 0 - maSize.height()/2, 0535 maSize.width(), maSize.height() ); 0536 painter->drawRect( rect ); 0537 break; 0538 } 0539 case MarkerAttributes::MarkerDiamond: 0540 { 0541 QVector <QPointF > diamondPoints; 0542 QPointF top, left, bottom, right; 0543 top = QPointF( 0, 0 - maSize.height()/2 ); 0544 left = QPointF( 0 - maSize.width()/2, 0 ); 0545 bottom = QPointF( 0, maSize.height()/2 ); 0546 right = QPointF( maSize.width()/2, 0 ); 0547 diamondPoints << top << left << bottom << right; 0548 painter->drawPolygon( diamondPoints ); 0549 break; 0550 } 0551 // both handled on top of the method: 0552 case MarkerAttributes::Marker1Pixel: 0553 case MarkerAttributes::Marker4Pixels: 0554 break; 0555 case MarkerAttributes::MarkerRing: 0556 { 0557 painter->setBrush( Qt::NoBrush ); 0558 painter->setPen( PrintingParameters::scalePen( QPen( brush.color() ) ) ); 0559 painter->drawEllipse( QRectF( 0 - maSize.height()/2, 0 - maSize.width()/2, 0560 maSize.height(), maSize.width()) ); 0561 break; 0562 } 0563 case MarkerAttributes::MarkerCross: 0564 { 0565 // Note: Markers can have outline, 0566 // so just drawing two rects is NOT the solution here! 0567 const qreal w02 = maSize.width() * 0.2; 0568 const qreal w05 = maSize.width() * 0.5; 0569 const qreal h02 = maSize.height()* 0.2; 0570 const qreal h05 = maSize.height()* 0.5; 0571 QVector <QPointF > crossPoints; 0572 QPointF p[12]; 0573 p[ 0] = QPointF( -w02, -h05 ); 0574 p[ 1] = QPointF( w02, -h05 ); 0575 p[ 2] = QPointF( w02, -h02 ); 0576 p[ 3] = QPointF( w05, -h02 ); 0577 p[ 4] = QPointF( w05, h02 ); 0578 p[ 5] = QPointF( w02, h02 ); 0579 p[ 6] = QPointF( w02, h05 ); 0580 p[ 7] = QPointF( -w02, h05 ); 0581 p[ 8] = QPointF( -w02, h02 ); 0582 p[ 9] = QPointF( -w05, h02 ); 0583 p[10] = QPointF( -w05, -h02 ); 0584 p[11] = QPointF( -w02, -h02 ); 0585 for ( int i=0; i<12; ++i ) 0586 crossPoints << p[i]; 0587 crossPoints << p[0]; 0588 painter->drawPolygon( crossPoints ); 0589 break; 0590 } 0591 case MarkerAttributes::MarkerFastCross: 0592 { 0593 QPointF left, right, top, bottom; 0594 left = QPointF( -maSize.width()/2, 0 ); 0595 right = QPointF( maSize.width()/2, 0 ); 0596 top = QPointF( 0, -maSize.height()/2 ); 0597 bottom= QPointF( 0, maSize.height()/2 ); 0598 painter->setPen( PrintingParameters::scalePen( QPen( brush.color() ) ) ); 0599 painter->drawLine( left, right ); 0600 painter->drawLine( top, bottom ); 0601 break; 0602 } 0603 case MarkerAttributes::MarkerArrowDown: 0604 { 0605 QVector <QPointF > arrowPoints; 0606 QPointF topLeft, topRight, bottom; 0607 topLeft = QPointF( 0 - maSize.width()/2, 0 - maSize.height()/2 ); 0608 topRight = QPointF( maSize.width()/2, 0 - maSize.height()/2 ); 0609 bottom = QPointF( 0, maSize.height()/2 ); 0610 arrowPoints << topLeft << bottom << topRight; 0611 painter->drawPolygon( arrowPoints ); 0612 break; 0613 } 0614 case MarkerAttributes::MarkerArrowUp: 0615 { 0616 QVector <QPointF > arrowPoints; 0617 QPointF top, bottomLeft, bottomRight; 0618 top = QPointF( 0, 0 - maSize.height()/2 ); 0619 bottomLeft = QPointF( 0 - maSize.width()/2, maSize.height()/2 ); 0620 bottomRight = QPointF( maSize.width()/2, maSize.height()/2 ); 0621 arrowPoints << top << bottomLeft << bottomRight; 0622 painter->drawPolygon( arrowPoints ); 0623 break; 0624 } 0625 case MarkerAttributes::MarkerArrowRight: 0626 { 0627 QVector <QPointF > arrowPoints; 0628 QPointF right, topLeft, bottomLeft; 0629 right = QPointF( maSize.width()/2, 0 ); 0630 topLeft = QPointF( 0 - maSize.width()/2, 0 - maSize.height()/2 ); 0631 bottomLeft = QPointF( 0 - maSize.width()/2, maSize.height()/2 ); 0632 arrowPoints << topLeft << bottomLeft << right; 0633 painter->drawPolygon( arrowPoints ); 0634 break; 0635 } 0636 case MarkerAttributes::MarkerArrowLeft: 0637 { 0638 QVector <QPointF > arrowPoints; 0639 QPointF left, topRight, bottomRight; 0640 left = QPointF( 0 - maSize.width()/2, 0 ); 0641 topRight = QPointF( maSize.width()/2, 0 - maSize.height()/2 ); 0642 bottomRight = QPointF( maSize.width()/2, maSize.height()/2 ); 0643 arrowPoints << left << bottomRight << topRight; 0644 painter->drawPolygon( arrowPoints ); 0645 break; 0646 } 0647 case MarkerAttributes::MarkerBowTie: 0648 case MarkerAttributes::MarkerHourGlass: 0649 { 0650 QVector <QPointF > points; 0651 QPointF topLeft, topRight, bottomLeft, bottomRight; 0652 topLeft = QPointF( 0 - maSize.width()/2, 0 - maSize.height()/2); 0653 topRight = QPointF( maSize.width()/2, 0 - maSize.height()/2 ); 0654 bottomLeft = QPointF( 0 - maSize.width()/2, maSize.height()/2 ); 0655 bottomRight = QPointF( maSize.width()/2, maSize.height()/2 ); 0656 if ( markerAttributes.markerStyle() == MarkerAttributes::MarkerBowTie) 0657 points << topLeft << bottomLeft << topRight << bottomRight; 0658 else 0659 points << topLeft << bottomRight << bottomLeft << topRight; 0660 painter->drawPolygon( points ); 0661 break; 0662 } 0663 case MarkerAttributes::MarkerStar: 0664 { 0665 const qreal w01 = maSize.width() * 0.1; 0666 const qreal w05 = maSize.width() * 0.5; 0667 const qreal h01 = maSize.height() * 0.1; 0668 const qreal h05 = maSize.height() * 0.5; 0669 QVector <QPointF > points; 0670 QPointF p1 = QPointF( 0, -h05 ); 0671 QPointF p2 = QPointF( -w01, -h01 ); 0672 QPointF p3 = QPointF( -w05, 0 ); 0673 QPointF p4 = QPointF( -w01, h01 ); 0674 QPointF p5 = QPointF( 0, h05 ); 0675 QPointF p6 = QPointF( w01, h01 ); 0676 QPointF p7 = QPointF( w05, 0 ); 0677 QPointF p8 = QPointF( w01, -h01 ); 0678 points << p1 << p2 << p3 << p4 << p5 << p6 << p7 << p8; 0679 painter->drawPolygon( points ); 0680 break; 0681 } 0682 case MarkerAttributes::MarkerX: 0683 { 0684 const qreal w01 = maSize.width() * 0.1; 0685 const qreal w04 = maSize.width() * 0.4; 0686 const qreal w05 = maSize.width() * 0.5; 0687 const qreal h01 = maSize.height() * 0.1; 0688 const qreal h04 = maSize.height() * 0.4; 0689 const qreal h05 = maSize.height() * 0.5; 0690 QVector <QPointF > crossPoints; 0691 QPointF p1 = QPointF( -w04, -h05 ); 0692 QPointF p2 = QPointF( -w05, -h04 ); 0693 QPointF p3 = QPointF( -w01, 0 ); 0694 QPointF p4 = QPointF( -w05, h04 ); 0695 QPointF p5 = QPointF( -w04, h05 ); 0696 QPointF p6 = QPointF( 0, h01 ); 0697 QPointF p7 = QPointF( w04, h05 ); 0698 QPointF p8 = QPointF( w05, h04 ); 0699 QPointF p9 = QPointF( w01, 0 ); 0700 QPointF p10 = QPointF( w05, -h04 ); 0701 QPointF p11 = QPointF( w04, -h05 ); 0702 QPointF p12 = QPointF( 0, -h01 ); 0703 crossPoints << p1 << p2 << p3 << p4 << p5 << p6 0704 << p7 << p8 << p9 << p10 << p11 << p12; 0705 painter->drawPolygon( crossPoints ); 0706 break; 0707 } 0708 case MarkerAttributes::MarkerAsterisk: 0709 { 0710 // Note: Markers can have outline, 0711 // so just drawing three lines is NOT the solution here! 0712 // The idea that we use is to draw 3 lines anyway, but convert their 0713 // outlines to QPainterPaths which are then united and filled. 0714 const qreal w04 = maSize.width() * 0.4; 0715 const qreal h02 = maSize.height() * 0.2; 0716 const qreal h05 = maSize.height() * 0.5; 0717 //QVector <QPointF > crossPoints; 0718 QPointF p1 = QPointF( 0, -h05 ); 0719 QPointF p2 = QPointF( -w04, -h02 ); 0720 QPointF p3 = QPointF( -w04, h02 ); 0721 QPointF p4 = QPointF( 0, h05 ); 0722 QPointF p5 = QPointF( w04, h02 ); 0723 QPointF p6 = QPointF( w04, -h02 ); 0724 QPen pen = painter->pen(); 0725 QPainterPathStroker stroker; 0726 stroker.setWidth( pen.widthF() ); 0727 stroker.setCapStyle( pen.capStyle() ); 0728 0729 QPainterPath path; 0730 QPainterPath dummyPath; 0731 dummyPath.moveTo( p1 ); 0732 dummyPath.lineTo( p4 ); 0733 path = stroker.createStroke( dummyPath ); 0734 0735 dummyPath = QPainterPath(); 0736 dummyPath.moveTo( p2 ); 0737 dummyPath.lineTo( p5 ); 0738 path = path.united( stroker.createStroke( dummyPath ) ); 0739 0740 dummyPath = QPainterPath(); 0741 dummyPath.moveTo( p3 ); 0742 dummyPath.lineTo( p6 ); 0743 path = path.united( stroker.createStroke( dummyPath ) ); 0744 0745 painter->drawPath( path ); 0746 break; 0747 } 0748 case MarkerAttributes::MarkerHorizontalBar: 0749 { 0750 const qreal w05 = maSize.width() * 0.5; 0751 const qreal h02 = maSize.height()* 0.2; 0752 QVector <QPointF > points; 0753 QPointF p1 = QPointF( -w05, -h02 ); 0754 QPointF p2 = QPointF( -w05, h02 ); 0755 QPointF p3 = QPointF( w05, h02 ); 0756 QPointF p4 = QPointF( w05, -h02 ); 0757 points << p1 << p2 << p3 << p4; 0758 painter->drawPolygon( points ); 0759 break; 0760 } 0761 case MarkerAttributes::MarkerVerticalBar: 0762 { 0763 const qreal w02 = maSize.width() * 0.2; 0764 const qreal h05 = maSize.height()* 0.5; 0765 QVector <QPointF > points; 0766 QPointF p1 = QPointF( -w02, -h05 ); 0767 QPointF p2 = QPointF( -w02, h05 ); 0768 QPointF p3 = QPointF( w02, h05 ); 0769 QPointF p4 = QPointF( w02, -h05 ); 0770 points << p1 << p2 << p3 << p4; 0771 painter->drawPolygon( points ); 0772 break; 0773 } 0774 case MarkerAttributes::NoMarker: 0775 break; 0776 case MarkerAttributes::PainterPathMarker: 0777 { 0778 QPainterPath path = markerAttributes.customMarkerPath(); 0779 const QRectF pathBoundingRect = path.boundingRect(); 0780 const qreal xScaling = maSize.height() / pathBoundingRect.height(); 0781 const qreal yScaling = maSize.width() / pathBoundingRect.width(); 0782 const qreal scaling = qMin( xScaling, yScaling ); 0783 painter->scale( scaling, scaling ); 0784 painter->setPen( PrintingParameters::scalePen( QPen( brush.color() ) ) ); 0785 painter->drawPath(path); 0786 break; 0787 } 0788 default: 0789 Q_ASSERT_X ( false, "paintMarkers()", 0790 "Type item does not match a defined Marker Type." ); 0791 } 0792 } 0793 painter->setPen( oldPen ); 0794 } 0795 0796 void AbstractDiagram::paintMarkers( QPainter* painter ) 0797 { 0798 if ( !checkInvariants() ) { 0799 return; 0800 } 0801 0802 const int rowCount = model()->rowCount( rootIndex() ); 0803 const int columnCount = model()->columnCount( rootIndex() ); 0804 for ( int column = 0; column < columnCount; column += datasetDimension() ) { 0805 for ( int row = 0; row < rowCount; ++row ) { 0806 QModelIndex index = model()->index( row, column, rootIndex() ); // checked 0807 qreal x; 0808 qreal y; 0809 if ( datasetDimension() == 1 ) { 0810 x = row; 0811 y = index.data().toReal(); 0812 } else { 0813 x = index.data().toReal(); 0814 y = model()->index( row, column + 1, rootIndex() ).data().toReal(); 0815 } 0816 paintMarker( painter, index, coordinatePlane()->translate( QPointF( x, y ) ) ); 0817 } 0818 } 0819 } 0820 0821 0822 void AbstractDiagram::setPen( const QModelIndex& index, const QPen& pen ) 0823 { 0824 attributesModel()->setData( 0825 conditionallyMapFromSource( index ), 0826 QVariant::fromValue( pen ), DatasetPenRole ); 0827 Q_EMIT propertiesChanged(); 0828 } 0829 0830 void AbstractDiagram::setPen( const QPen& pen ) 0831 { 0832 attributesModel()->setModelData( 0833 QVariant::fromValue( pen ), DatasetPenRole ); 0834 Q_EMIT propertiesChanged(); 0835 } 0836 0837 void AbstractDiagram::setPen( int dataset, const QPen& pen ) 0838 { 0839 d->setDatasetAttrs( dataset, QVariant::fromValue( pen ), DatasetPenRole ); 0840 Q_EMIT propertiesChanged(); 0841 } 0842 0843 QPen AbstractDiagram::pen() const 0844 { 0845 return attributesModel()->data( DatasetPenRole ).value< QPen >(); 0846 } 0847 0848 QPen AbstractDiagram::pen( int dataset ) const 0849 { 0850 const QVariant penSettings( d->datasetAttrs( dataset, DatasetPenRole ) ); 0851 if ( penSettings.isValid() ) 0852 return penSettings.value< QPen >(); 0853 return pen(); 0854 } 0855 0856 QPen AbstractDiagram::pen( const QModelIndex& index ) const 0857 { 0858 return attributesModel()->data( 0859 conditionallyMapFromSource( index ), 0860 DatasetPenRole ).value< QPen >(); 0861 } 0862 0863 void AbstractDiagram::setBrush( const QModelIndex& index, const QBrush& brush ) 0864 { 0865 attributesModel()->setData( 0866 conditionallyMapFromSource( index ), 0867 QVariant::fromValue( brush ), DatasetBrushRole ); 0868 Q_EMIT propertiesChanged(); 0869 } 0870 0871 void AbstractDiagram::setBrush( const QBrush& brush ) 0872 { 0873 attributesModel()->setModelData( 0874 QVariant::fromValue( brush ), DatasetBrushRole ); 0875 Q_EMIT propertiesChanged(); 0876 } 0877 0878 void AbstractDiagram::setBrush( int dataset, const QBrush& brush ) 0879 { 0880 d->setDatasetAttrs( dataset, QVariant::fromValue( brush ), DatasetBrushRole ); 0881 Q_EMIT propertiesChanged(); 0882 } 0883 0884 QBrush AbstractDiagram::brush() const 0885 { 0886 return attributesModel()->data( DatasetBrushRole ).value< QBrush >(); 0887 } 0888 0889 QBrush AbstractDiagram::brush( int dataset ) const 0890 { 0891 const QVariant brushSettings( d->datasetAttrs( dataset, DatasetBrushRole ) ); 0892 if ( brushSettings.isValid() ) 0893 return brushSettings.value< QBrush >(); 0894 return brush(); 0895 } 0896 0897 QBrush AbstractDiagram::brush( const QModelIndex& index ) const 0898 { 0899 return 0900 attributesModel()->data( conditionallyMapFromSource( index ), DatasetBrushRole ).value< QBrush >(); 0901 } 0902 0903 /* 0904 * Sets the unit prefix for one value 0905 * @param prefix the prefix to be set 0906 * @param column the value using that prefix 0907 * @param orientation the orientantion of the axis to set 0908 */ 0909 void AbstractDiagram::setUnitPrefix( const QString& prefix, int column, Qt::Orientation orientation ) 0910 { 0911 d->unitPrefixMap[ column ][ orientation ]= prefix; 0912 } 0913 0914 /* 0915 * Sets the unit prefix for all values 0916 * @param prefix the prefix to be set 0917 * @param orientation the orientantion of the axis to set 0918 */ 0919 void AbstractDiagram::setUnitPrefix( const QString& prefix, Qt::Orientation orientation ) 0920 { 0921 d->unitPrefix[ orientation ] = prefix; 0922 } 0923 0924 /* 0925 * Sets the unit suffix for one value 0926 * @param suffix the suffix to be set 0927 * @param column the value using that suffix 0928 * @param orientation the orientantion of the axis to set 0929 */ 0930 void AbstractDiagram::setUnitSuffix( const QString& suffix, int column, Qt::Orientation orientation ) 0931 { 0932 d->unitSuffixMap[ column ][ orientation ]= suffix; 0933 } 0934 0935 /* 0936 * Sets the unit suffix for all values 0937 * @param suffix the suffix to be set 0938 * @param orientation the orientantion of the axis to set 0939 */ 0940 void AbstractDiagram::setUnitSuffix( const QString& suffix, Qt::Orientation orientation ) 0941 { 0942 d->unitSuffix[ orientation ] = suffix; 0943 } 0944 0945 /* 0946 * Returns the unit prefix for a special value 0947 * @param column the value which's prefix is requested 0948 * @param orientation the orientation of the axis 0949 * @param fallback if true, the global prefix is return when no specific one is set for that value 0950 * @return the unit prefix 0951 */ 0952 QString AbstractDiagram::unitPrefix( int column, Qt::Orientation orientation, bool fallback ) const 0953 { 0954 if ( !fallback || d->unitPrefixMap[ column ].contains( orientation ) ) 0955 return d->unitPrefixMap[ column ][ orientation ]; 0956 return d->unitPrefix[ orientation ]; 0957 } 0958 0959 /* Returns the global unit prefix 0960 * @param orientation the orientation of the axis 0961 * @return the unit prefix 0962 */ 0963 QString AbstractDiagram::unitPrefix( Qt::Orientation orientation ) const 0964 { 0965 return d->unitPrefix[ orientation ]; 0966 } 0967 0968 /* 0969 * Returns the unit suffix for a special value 0970 * @param column the value which's suffix is requested 0971 * @param orientation the orientation of the axis 0972 * @param fallback if true, the global suffix is return when no specific one is set for that value 0973 * @return the unit suffix 0974 */ 0975 QString AbstractDiagram::unitSuffix( int column, Qt::Orientation orientation, bool fallback ) const 0976 { 0977 if ( !fallback || d->unitSuffixMap[ column ].contains( orientation ) ) 0978 return d->unitSuffixMap[ column ][ orientation ]; 0979 return d->unitSuffix[ orientation ]; 0980 } 0981 0982 /* Returns the global unit suffix 0983 * @param orientation the orientation of the axis 0984 * @return the unit suffix 0985 */ 0986 QString AbstractDiagram::unitSuffix( Qt::Orientation orientation ) const 0987 { 0988 return d->unitSuffix[ orientation ]; 0989 } 0990 0991 // implement QAbstractItemView: 0992 QRect AbstractDiagram::visualRect( const QModelIndex &index ) const 0993 { 0994 return d->reverseMapper.boundingRect( index.row(), index.column() ).toRect(); 0995 } 0996 0997 void AbstractDiagram::scrollTo(const QModelIndex &, ScrollHint ) 0998 {} 0999 1000 // indexAt ... down below 1001 1002 QModelIndex AbstractDiagram::moveCursor(CursorAction, Qt::KeyboardModifiers ) 1003 { return QModelIndex(); } 1004 1005 int AbstractDiagram::horizontalOffset() const 1006 { return 0; } 1007 1008 int AbstractDiagram::verticalOffset() const 1009 { return 0; } 1010 1011 bool AbstractDiagram::isIndexHidden(const QModelIndex &) const 1012 { return true; } 1013 1014 void AbstractDiagram::setSelection(const QRect& rect , QItemSelectionModel::SelectionFlags command ) 1015 { 1016 const QModelIndexList indexes = d->indexesIn( rect ); 1017 QItemSelection selection; 1018 for ( const QModelIndex& index : indexes ) 1019 { 1020 selection.append( QItemSelectionRange( index ) ); 1021 } 1022 selectionModel()->select( selection, command ); 1023 } 1024 1025 QRegion AbstractDiagram::visualRegionForSelection(const QItemSelection &selection) const 1026 { 1027 QPolygonF polygon; 1028 const auto indexes = selection.indexes(); 1029 polygon.reserve(indexes.count()); 1030 for ( const QModelIndex& index : indexes ) 1031 { 1032 polygon << d->reverseMapper.polygon(index.row(), index.column()); 1033 } 1034 return polygon.isEmpty() ? QRegion() : QRegion( polygon.toPolygon() ); 1035 } 1036 1037 QRegion AbstractDiagram::visualRegion(const QModelIndex &index) const 1038 { 1039 QPolygonF polygon = d->reverseMapper.polygon(index.row(), index.column()); 1040 return polygon.isEmpty() ? QRegion() : QRegion( polygon.toPolygon() ); 1041 } 1042 1043 void KChart::AbstractDiagram::useDefaultColors( ) 1044 { 1045 d->attributesModel->setPaletteType( AttributesModel::PaletteTypeDefault ); 1046 } 1047 1048 void KChart::AbstractDiagram::useSubduedColors( ) 1049 { 1050 d->attributesModel->setPaletteType( AttributesModel::PaletteTypeSubdued ); 1051 } 1052 1053 void KChart::AbstractDiagram::useRainbowColors( ) 1054 { 1055 d->attributesModel->setPaletteType( AttributesModel::PaletteTypeRainbow ); 1056 } 1057 1058 QStringList AbstractDiagram::itemRowLabels() const 1059 { 1060 QStringList ret; 1061 if ( model() ) { 1062 //qDebug() << "AbstractDiagram::itemRowLabels(): " << attributesModel()->rowCount(attributesModelRootIndex()) << "entries"; 1063 const int rowCount = attributesModel()->rowCount(attributesModelRootIndex()); 1064 for ( int i = 0; i < rowCount; ++i ) { 1065 //qDebug() << "item row label: " << attributesModel()->headerData( i, Qt::Vertical, Qt::DisplayRole ).toString(); 1066 ret << unitPrefix( i, Qt::Horizontal, true ) + 1067 attributesModel()->headerData( i, Qt::Vertical, Qt::DisplayRole ).toString() + 1068 unitSuffix( i, Qt::Horizontal, true ); 1069 } 1070 } 1071 return ret; 1072 } 1073 1074 QStringList AbstractDiagram::datasetLabels() const 1075 { 1076 QStringList ret; 1077 if ( !model() ) { 1078 return ret; 1079 } 1080 const int datasetCount = d->datasetCount(); 1081 for ( int i = 0; i < datasetCount; ++i ) { 1082 ret << d->datasetAttrs( i, Qt::DisplayRole ).toString(); 1083 } 1084 return ret; 1085 } 1086 1087 QList<QBrush> AbstractDiagram::datasetBrushes() const 1088 { 1089 QList<QBrush> ret; 1090 if ( !model() ) { 1091 return ret; 1092 } 1093 const int datasetCount = d->datasetCount(); 1094 for ( int i = 0; i < datasetCount; ++i ) { 1095 ret << brush( i ); 1096 } 1097 return ret; 1098 } 1099 1100 QList<QPen> AbstractDiagram::datasetPens() const 1101 { 1102 QList<QPen> ret; 1103 if ( !model() ) { 1104 return ret; 1105 } 1106 const int datasetCount = d->datasetCount(); 1107 for ( int i = 0; i < datasetCount; ++i ) { 1108 ret << pen( i ); 1109 } 1110 return ret; 1111 } 1112 1113 QList<MarkerAttributes> AbstractDiagram::datasetMarkers() const 1114 { 1115 QList<MarkerAttributes> ret; 1116 if ( !model() ) { 1117 return ret; 1118 } 1119 const int datasetCount = d->datasetCount(); 1120 for ( int i = 0; i < datasetCount; ++i ) { 1121 ret << dataValueAttributes( i ).markerAttributes(); 1122 } 1123 return ret; 1124 } 1125 1126 bool AbstractDiagram::checkInvariants( bool justReturnTheStatus ) const 1127 { 1128 if ( ! justReturnTheStatus ) { 1129 Q_ASSERT_X ( model(), "AbstractDiagram::checkInvariants()", 1130 "There is no usable model set, for the diagram." ); 1131 1132 Q_ASSERT_X ( coordinatePlane(), "AbstractDiagram::checkInvariants()", 1133 "There is no usable coordinate plane set, for the diagram." ); 1134 } 1135 return model() && coordinatePlane(); 1136 } 1137 1138 int AbstractDiagram::datasetDimension( ) const 1139 { 1140 return d->datasetDimension; 1141 } 1142 1143 void AbstractDiagram::setDatasetDimension( int dimension ) 1144 { 1145 Q_UNUSED( dimension ); 1146 qDebug() << "Setting the dataset dimension using AbstractDiagram::setDatasetDimension is " 1147 "obsolete. Use the specific diagram types instead."; 1148 } 1149 1150 void AbstractDiagram::setDatasetDimensionInternal( int dimension ) 1151 { 1152 Q_ASSERT( dimension != 0 ); 1153 if ( d->datasetDimension == dimension ) { 1154 return; 1155 } 1156 d->datasetDimension = dimension; 1157 d->attributesModel->setDatasetDimension( dimension ); 1158 setDataBoundariesDirty(); 1159 Q_EMIT layoutChanged( this ); 1160 } 1161 1162 qreal AbstractDiagram::valueForCell( int row, int column ) const 1163 { 1164 if ( !d->attributesModel->hasIndex( row, column, attributesModelRootIndex() ) ) { 1165 qWarning() << "AbstractDiagram::valueForCell(): Requesting value for invalid index!"; 1166 return std::numeric_limits<qreal>::quiet_NaN(); 1167 } 1168 return d->attributesModel->data( 1169 d->attributesModel->index( row, column, attributesModelRootIndex() ) ).toReal(); // checked 1170 } 1171 1172 void AbstractDiagram::update() const 1173 { 1174 if ( d->plane ) { 1175 d->plane->update(); 1176 } 1177 } 1178 1179 QModelIndex AbstractDiagram::indexAt( const QPoint& point ) const 1180 { 1181 return d->indexAt( point ); 1182 } 1183 1184 QModelIndexList AbstractDiagram::indexesAt( const QPoint& point ) const 1185 { 1186 return d->indexesAt( point ); 1187 } 1188 1189 QModelIndexList AbstractDiagram::indexesIn( const QRect& rect ) const 1190 { 1191 return d->indexesIn( rect ); 1192 }