File indexing completed on 2024-12-15 04:02:28
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 "KChartBarDiagram.h" 0010 #include "KChartBarDiagram_p.h" 0011 0012 #include "KChartThreeDBarAttributes.h" 0013 #include "KChartPosition.h" 0014 #include "KChartAttributesModel.h" 0015 #include "KChartAbstractGrid.h" 0016 #include "KChartPainterSaver_p.h" 0017 0018 #include <QPainter> 0019 #include <QDebug> 0020 0021 #include "KChartNormalBarDiagram_p.h" 0022 #include "KChartStackedBarDiagram_p.h" 0023 #include "KChartPercentBarDiagram_p.h" 0024 #include "KChartNormalLyingBarDiagram_p.h" 0025 #include "KChartStackedLyingBarDiagram_p.h" 0026 #include "KChartPercentLyingBarDiagram_p.h" 0027 #include "KChartMath_p.h" 0028 0029 0030 using namespace KChart; 0031 0032 BarDiagram::Private::Private() 0033 : orientation( Qt::Vertical ) 0034 , implementor( nullptr ) 0035 , normalDiagram( nullptr ) 0036 , stackedDiagram( nullptr ) 0037 , percentDiagram( nullptr ) 0038 , normalLyingDiagram( nullptr ) 0039 , stackedLyingDiagram( nullptr ) 0040 , percentLyingDiagram( nullptr ) 0041 { 0042 } 0043 0044 BarDiagram::Private::~Private() 0045 { 0046 delete normalDiagram; 0047 delete stackedDiagram; 0048 delete percentDiagram; 0049 delete normalLyingDiagram; 0050 delete stackedLyingDiagram; 0051 delete percentLyingDiagram; 0052 } 0053 0054 void BarDiagram::Private::setOrientationAndType( Qt::Orientation o, BarDiagram::BarType type ) 0055 { 0056 if ( orientation == o && implementor->type() == type ) { 0057 return; 0058 } 0059 BarDiagram *barDia = qobject_cast< BarDiagram * >( diagram ); 0060 0061 orientation = o; 0062 0063 if ( orientation == Qt::Vertical ) { 0064 switch ( type ) { 0065 case Normal: 0066 implementor = normalDiagram; 0067 break; 0068 case Stacked: 0069 implementor = stackedDiagram; 0070 break; 0071 case Percent: 0072 implementor = percentDiagram; 0073 break; 0074 default: 0075 Q_ASSERT_X( false, "BarDiagram::setType", "unknown diagram subtype" ); 0076 } 0077 } else { 0078 switch ( type ) { 0079 case Normal: 0080 implementor = normalLyingDiagram; 0081 break; 0082 case Stacked: 0083 implementor = stackedLyingDiagram; 0084 break; 0085 case Percent: 0086 implementor = percentLyingDiagram; 0087 break; 0088 default: 0089 Q_ASSERT_X( false, "BarDiagram::setType", "unknown diagram subtype" ); 0090 } 0091 } 0092 0093 Q_ASSERT( implementor->type() == type ); 0094 0095 // AbstractAxis settings - see AbstractDiagram and CartesianAxis 0096 barDia->setPercentMode( type == BarDiagram::Percent ); 0097 barDia->setDataBoundariesDirty(); 0098 Q_EMIT barDia->layoutChanged( barDia ); 0099 Q_EMIT barDia->propertiesChanged(); 0100 } 0101 0102 #define d d_func() 0103 0104 0105 BarDiagram::BarDiagram( QWidget* parent, CartesianCoordinatePlane* plane ) : 0106 AbstractCartesianDiagram( new Private(), parent, plane ) 0107 { 0108 init(); 0109 } 0110 0111 void BarDiagram::init() 0112 { 0113 d->normalDiagram = new NormalBarDiagram( this ); 0114 d->stackedDiagram = new StackedBarDiagram( this ); 0115 d->percentDiagram = new PercentBarDiagram( this ); 0116 d->normalLyingDiagram = new NormalLyingBarDiagram( this ); 0117 d->stackedLyingDiagram = new StackedLyingBarDiagram( this ); 0118 d->percentLyingDiagram = new PercentLyingBarDiagram( this ); 0119 d->implementor = d->normalDiagram; 0120 d->compressor.setModel( attributesModel() ); 0121 } 0122 0123 BarDiagram::~BarDiagram() 0124 { 0125 } 0126 0127 BarDiagram * BarDiagram::clone() const 0128 { 0129 0130 BarDiagram* newDiagram = new BarDiagram( new Private( *d ) ); 0131 newDiagram->setType( type() ); 0132 return newDiagram; 0133 } 0134 0135 bool BarDiagram::compare( const BarDiagram* other ) const 0136 { 0137 if ( other == this ) return true; 0138 if ( ! other ) { 0139 return false; 0140 } 0141 0142 return // compare the base class 0143 ( static_cast<const AbstractCartesianDiagram*>(this)->compare( other ) ) && 0144 // compare own properties 0145 (type() == other->type()); 0146 } 0147 0148 void BarDiagram::setType( const BarType type ) 0149 { 0150 d->setOrientationAndType( d->orientation, type ); 0151 } 0152 0153 BarDiagram::BarType BarDiagram::type() const 0154 { 0155 return d->implementor->type(); 0156 } 0157 0158 void BarDiagram::setOrientation( Qt::Orientation orientation ) 0159 { 0160 d->setOrientationAndType( orientation, d->implementor->type() ); 0161 } 0162 0163 Qt::Orientation BarDiagram::orientation() const 0164 { 0165 return d->orientation; 0166 } 0167 0168 void BarDiagram::setBarAttributes( const BarAttributes& ba ) 0169 { 0170 d->attributesModel->setModelData( QVariant::fromValue( ba ), BarAttributesRole ); 0171 Q_EMIT propertiesChanged(); 0172 } 0173 0174 void BarDiagram::setBarAttributes( int column, const BarAttributes& ba ) 0175 { 0176 d->setDatasetAttrs( column, QVariant::fromValue( ba ), BarAttributesRole ); 0177 Q_EMIT propertiesChanged(); 0178 } 0179 0180 void BarDiagram::setBarAttributes( const QModelIndex& index, const BarAttributes& ba ) 0181 { 0182 attributesModel()->setData( 0183 d->attributesModel->mapFromSource( index ), 0184 QVariant::fromValue( ba ), 0185 BarAttributesRole ); 0186 Q_EMIT propertiesChanged(); 0187 } 0188 0189 BarAttributes BarDiagram::barAttributes() const 0190 { 0191 return d->attributesModel->data( KChart::BarAttributesRole ).value<BarAttributes>(); 0192 } 0193 0194 BarAttributes BarDiagram::barAttributes( int column ) const 0195 { 0196 const QVariant attrs( d->datasetAttrs( column, KChart::BarAttributesRole ) ); 0197 if ( attrs.isValid() ) 0198 return attrs.value<BarAttributes>(); 0199 return barAttributes(); 0200 } 0201 0202 BarAttributes BarDiagram::barAttributes( const QModelIndex& index ) const 0203 { 0204 return d->attributesModel->data( 0205 d->attributesModel->mapFromSource( index ), 0206 KChart::BarAttributesRole ).value<BarAttributes>(); 0207 } 0208 0209 void BarDiagram::setThreeDBarAttributes( const ThreeDBarAttributes& threeDAttrs ) 0210 { 0211 setDataBoundariesDirty(); 0212 d->attributesModel->setModelData( QVariant::fromValue( threeDAttrs ), ThreeDBarAttributesRole ); 0213 Q_EMIT layoutChanged( this ); 0214 Q_EMIT propertiesChanged(); 0215 } 0216 0217 void BarDiagram::setThreeDBarAttributes( int column, const ThreeDBarAttributes& threeDAttrs ) 0218 { 0219 setDataBoundariesDirty(); 0220 d->setDatasetAttrs( column, QVariant::fromValue( threeDAttrs ), ThreeDBarAttributesRole ); 0221 //Q_EMIT layoutChanged( this ); 0222 Q_EMIT propertiesChanged(); 0223 } 0224 0225 void BarDiagram::setThreeDBarAttributes( const QModelIndex& index, const ThreeDBarAttributes& threeDAttrs ) 0226 { 0227 setDataBoundariesDirty(); 0228 d->attributesModel->setData( 0229 d->attributesModel->mapFromSource(index), 0230 QVariant::fromValue( threeDAttrs ), 0231 ThreeDBarAttributesRole ); 0232 //Q_EMIT layoutChanged( this ); 0233 Q_EMIT propertiesChanged(); 0234 } 0235 0236 ThreeDBarAttributes BarDiagram::threeDBarAttributes() const 0237 { 0238 return d->attributesModel->data( KChart::ThreeDBarAttributesRole ).value<ThreeDBarAttributes>(); 0239 } 0240 0241 ThreeDBarAttributes BarDiagram::threeDBarAttributes( int column ) const 0242 { 0243 const QVariant attrs( d->datasetAttrs( column, KChart::ThreeDBarAttributesRole ) ); 0244 if ( attrs.isValid() ) 0245 return attrs.value<ThreeDBarAttributes>(); 0246 return threeDBarAttributes(); 0247 } 0248 0249 ThreeDBarAttributes BarDiagram::threeDBarAttributes( const QModelIndex& index ) const 0250 { 0251 return d->attributesModel->data( 0252 d->attributesModel->mapFromSource(index), 0253 KChart::ThreeDBarAttributesRole ).value<ThreeDBarAttributes>(); 0254 } 0255 0256 qreal BarDiagram::threeDItemDepth( const QModelIndex& index ) const 0257 { 0258 return threeDBarAttributes( index ).validDepth(); 0259 } 0260 0261 qreal BarDiagram::threeDItemDepth( int column ) const 0262 { 0263 return threeDBarAttributes( column ).validDepth(); 0264 } 0265 0266 void BarDiagram::resizeEvent ( QResizeEvent*) 0267 { 0268 0269 } 0270 0271 const QPair<QPointF, QPointF> BarDiagram::calculateDataBoundaries() const 0272 { 0273 d->compressor.setResolution( static_cast<int>( this->size().width() * coordinatePlane()->zoomFactorX() ), 0274 static_cast<int>( this->size().height() * coordinatePlane()->zoomFactorY() ) ); 0275 0276 if ( !checkInvariants( true ) ) { 0277 return QPair< QPointF, QPointF >( QPointF( 0, 0 ), QPointF( 0, 0 ) ); 0278 } 0279 0280 // note: calculateDataBoundaries() is ignoring the hidden flags. 0281 // That's not a bug but a feature: Hiding data does not mean removing them. 0282 // For totally removing data from KD Chart's view people can use e.g. a proxy model 0283 // calculate boundaries for different line types Normal - Stacked - Percent - Default Normal 0284 return d->implementor->calculateDataBoundaries(); 0285 } 0286 0287 void BarDiagram::paintEvent ( QPaintEvent*) 0288 { 0289 QPainter painter ( viewport() ); 0290 PaintContext ctx; 0291 ctx.setPainter ( &painter ); 0292 ctx.setRectangle( QRectF ( 0, 0, width(), height() ) ); 0293 paint ( &ctx ); 0294 } 0295 0296 void BarDiagram::paint( PaintContext* ctx ) 0297 { 0298 if ( !checkInvariants( true ) ) return; 0299 if ( !AbstractGrid::isBoundariesValid(dataBoundaries()) ) return; 0300 const PainterSaver p( ctx->painter() ); 0301 if ( model()->rowCount( rootIndex() ) == 0 || model()->columnCount( rootIndex() ) == 0 ) 0302 return; // nothing to paint for us 0303 0304 AbstractCoordinatePlane* const plane = ctx->coordinatePlane(); 0305 ctx->setCoordinatePlane( plane->sharedAxisMasterPlane( ctx->painter() ) ); 0306 0307 // This was intended as a fix for KDCH-515, however it caused KDCH-816 0308 // and the original problem in KDCH-515 had by then been fixed in another way. 0309 // Bottom line is, this code is wrong because the above call to 0310 // plane->sharedAxisMasterPlane() performs a translation of the painter, which 0311 // also translates the clip rect, so if we set the old clip rect again afterwards, 0312 // we get a wrong clipping. 0313 // Also, this code is unnecessary because CartesianCoordinatePlane::paint() 0314 // already sets the clipping properly before calling this method. 0315 // ctx->painter()->setClipping( true ); 0316 // ctx->painter()->setClipRect( ctx->rectangle() ); 0317 0318 // paint different bar types Normal - Stacked - Percent - Default Normal 0319 d->implementor->paint( ctx ); 0320 0321 ctx->setCoordinatePlane( plane ); 0322 } 0323 0324 void BarDiagram::resize( const QSizeF& size ) 0325 { 0326 d->compressor.setResolution( static_cast< int >( size.width() * coordinatePlane()->zoomFactorX() ), 0327 static_cast< int >( size.height() * coordinatePlane()->zoomFactorY() ) ); 0328 setDataBoundariesDirty(); 0329 AbstractCartesianDiagram::resize( size ); 0330 } 0331 0332 #if defined(Q_COMPILER_MANGLES_RETURN_TYPE) 0333 const 0334 #endif 0335 int BarDiagram::numberOfAbscissaSegments () const 0336 { 0337 return d->attributesModel->rowCount(attributesModelRootIndex()); 0338 } 0339 0340 #if defined(Q_COMPILER_MANGLES_RETURN_TYPE) 0341 const 0342 #endif 0343 int BarDiagram::numberOfOrdinateSegments () const 0344 { 0345 return d->attributesModel->columnCount(attributesModelRootIndex()); 0346 } 0347 0348 //#undef d