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