File indexing completed on 2024-12-15 04:02:33
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 "KChartStockDiagram.h" 0010 #include "KChartStockDiagram_p.h" 0011 0012 #include "KChartPaintContext.h" 0013 #include "KChartPainterSaver_p.h" 0014 0015 using namespace KChart; 0016 0017 #define d d_func() 0018 0019 StockDiagram::StockDiagram( QWidget *parent, CartesianCoordinatePlane *plane ) 0020 : AbstractCartesianDiagram( new Private(), parent, plane ) 0021 { 0022 init(); 0023 } 0024 0025 StockDiagram::~StockDiagram() 0026 { 0027 } 0028 0029 /* 0030 * Initializes the diagram 0031 */ 0032 void StockDiagram::init() 0033 { 0034 d->diagram = this; 0035 d->compressor.setModel( attributesModel() ); 0036 0037 // Set properties to defaults 0038 d->type = HighLowClose; 0039 d->upTrendCandlestickBrush = QBrush( Qt::white ); 0040 d->downTrendCandlestickBrush = QBrush( Qt::black ); 0041 d->upTrendCandlestickPen = QPen( Qt::black ); 0042 d->downTrendCandlestickPen = QPen( Qt::black ); 0043 0044 d->lowHighLinePen = QPen( Qt::black ); 0045 setDatasetDimensionInternal( 3 ); 0046 //setDatasetDimension( 3 ); 0047 0048 setPen( QPen( Qt::black ) ); 0049 } 0050 0051 void StockDiagram::setType( Type type ) 0052 { 0053 d->type = type; 0054 Q_EMIT propertiesChanged(); 0055 } 0056 0057 StockDiagram::Type StockDiagram::type() const 0058 { 0059 return d->type; 0060 } 0061 0062 void StockDiagram::setStockBarAttributes( const StockBarAttributes &attr ) 0063 { 0064 attributesModel()->setModelData( 0065 QVariant::fromValue( attr ), 0066 StockBarAttributesRole ); 0067 Q_EMIT propertiesChanged(); 0068 } 0069 0070 StockBarAttributes StockDiagram::stockBarAttributes() const 0071 { 0072 return attributesModel()->modelData( StockBarAttributesRole ).value<StockBarAttributes>(); 0073 } 0074 0075 void StockDiagram::setStockBarAttributes( int column, const StockBarAttributes &attr ) 0076 { 0077 d->setDatasetAttrs( column, QVariant::fromValue( attr ), StockBarAttributesRole ); 0078 Q_EMIT propertiesChanged(); 0079 } 0080 0081 StockBarAttributes StockDiagram::stockBarAttributes( int column ) const 0082 { 0083 const QVariant attr( d->datasetAttrs( column, StockBarAttributesRole ) ); 0084 if ( attr.isValid() ) 0085 return attr.value<StockBarAttributes>(); 0086 return stockBarAttributes(); 0087 } 0088 0089 void StockDiagram::setThreeDBarAttributes( const ThreeDBarAttributes &attr ) 0090 { 0091 attributesModel()->setModelData( 0092 QVariant::fromValue( attr ), 0093 ThreeDBarAttributesRole ); 0094 Q_EMIT propertiesChanged(); 0095 } 0096 0097 ThreeDBarAttributes StockDiagram::threeDBarAttributes() const 0098 { 0099 return attributesModel()->modelData( ThreeDBarAttributesRole ).value<ThreeDBarAttributes>(); 0100 } 0101 0102 void StockDiagram::setThreeDBarAttributes( int column, const ThreeDBarAttributes &attr ) 0103 { 0104 d->setDatasetAttrs( column, QVariant::fromValue( attr ), StockBarAttributesRole ); 0105 Q_EMIT propertiesChanged(); 0106 } 0107 0108 ThreeDBarAttributes StockDiagram::threeDBarAttributes( int column ) const 0109 { 0110 const QVariant attr( d->datasetAttrs( column, ThreeDBarAttributesRole ) ); 0111 if ( attr.isValid() ) 0112 return attr.value<ThreeDBarAttributes>(); 0113 return threeDBarAttributes(); 0114 } 0115 0116 0117 void StockDiagram::setLowHighLinePen( const QPen &pen ) 0118 { 0119 d->lowHighLinePen = pen; 0120 } 0121 0122 QPen StockDiagram::lowHighLinePen() const 0123 { 0124 return d->lowHighLinePen; 0125 } 0126 0127 void StockDiagram::setLowHighLinePen( int column, const QPen &pen ) 0128 { 0129 d->lowHighLinePens[column] = pen; 0130 } 0131 0132 QPen StockDiagram::lowHighLinePen( int column ) const 0133 { 0134 if ( d->lowHighLinePens.contains( column ) ) 0135 return d->lowHighLinePens[column]; 0136 return d->lowHighLinePen; 0137 } 0138 0139 void StockDiagram::setUpTrendCandlestickBrush( const QBrush &brush ) 0140 { 0141 d->upTrendCandlestickBrush = brush; 0142 } 0143 0144 QBrush StockDiagram::upTrendCandlestickBrush() const 0145 { 0146 return d->upTrendCandlestickBrush; 0147 } 0148 0149 void StockDiagram::setDownTrendCandlestickBrush( const QBrush &brush ) 0150 { 0151 d->downTrendCandlestickBrush = brush; 0152 } 0153 0154 QBrush StockDiagram::downTrendCandlestickBrush() const 0155 { 0156 return d->downTrendCandlestickBrush; 0157 } 0158 0159 void StockDiagram::setUpTrendCandlestickBrush( int column, const QBrush &brush ) 0160 { 0161 d->upTrendCandlestickBrushes[column] = brush; 0162 } 0163 0164 QBrush StockDiagram::upTrendCandlestickBrush( int column ) const 0165 { 0166 if ( d->upTrendCandlestickBrushes.contains( column ) ) 0167 return d->upTrendCandlestickBrushes[column]; 0168 return d->upTrendCandlestickBrush; 0169 } 0170 0171 void StockDiagram::setDownTrendCandlestickBrush( int column, const QBrush &brush ) 0172 { 0173 d->downTrendCandlestickBrushes[column] = brush; 0174 } 0175 0176 QBrush StockDiagram::downTrendCandlestickBrush( int column ) const 0177 { 0178 if ( d->downTrendCandlestickBrushes.contains( column ) ) 0179 return d->downTrendCandlestickBrushes[column]; 0180 return d->downTrendCandlestickBrush; 0181 } 0182 0183 0184 void StockDiagram::setUpTrendCandlestickPen( const QPen &pen ) 0185 { 0186 d->upTrendCandlestickPen = pen; 0187 } 0188 0189 QPen StockDiagram::upTrendCandlestickPen() const 0190 { 0191 return d->upTrendCandlestickPen; 0192 } 0193 0194 void StockDiagram::setDownTrendCandlestickPen( const QPen &pen ) 0195 { 0196 d->downTrendCandlestickPen = pen; 0197 } 0198 0199 QPen StockDiagram::downTrendCandlestickPen() const 0200 { 0201 return d->downTrendCandlestickPen; 0202 } 0203 0204 void StockDiagram::setUpTrendCandlestickPen( int column, const QPen &pen ) 0205 { 0206 d->upTrendCandlestickPens[column] = pen; 0207 } 0208 0209 QPen StockDiagram::upTrendCandlestickPen( int column ) const 0210 { 0211 if ( d->upTrendCandlestickPens.contains( column ) ) 0212 return d->upTrendCandlestickPens[column]; 0213 return d->upTrendCandlestickPen; 0214 } 0215 0216 void StockDiagram::setDownTrendCandlestickPen( int column, const QPen &pen ) 0217 { 0218 d->downTrendCandlestickPens[column] = pen; 0219 } 0220 0221 QPen StockDiagram::downTrendCandlestickPen( int column ) const 0222 { 0223 if ( d->downTrendCandlestickPens.contains( column ) ) 0224 return d->downTrendCandlestickPens[column]; 0225 return d->downTrendCandlestickPen; 0226 } 0227 0228 #if defined(Q_COMPILER_MANGLES_RETURN_TYPE) 0229 const 0230 #endif 0231 int StockDiagram::numberOfAbscissaSegments() const { return 1; } 0232 0233 #if defined(Q_COMPILER_MANGLES_RETURN_TYPE) 0234 const 0235 #endif 0236 int StockDiagram::numberOfOrdinateSegments() const { return 1; } 0237 0238 void StockDiagram::paint( PaintContext *context ) 0239 { 0240 // Clear old reverse mapping data and create new 0241 // reverse mapping scene 0242 d->reverseMapper.clear(); 0243 0244 PainterSaver painterSaver( context->painter() ); 0245 const int rowCount = attributesModel()->rowCount( attributesModelRootIndex() ); 0246 const int divisor = ( d->type == OpenHighLowClose || d->type == Candlestick ) ? 4 : 3; 0247 const int colCount = attributesModel()->columnCount( attributesModelRootIndex() ) / divisor; 0248 for ( int col = 0; col < colCount; ++col ) 0249 { 0250 for ( int row = 0; row < rowCount; row++ ) { 0251 CartesianDiagramDataCompressor::DataPoint low; 0252 CartesianDiagramDataCompressor::DataPoint high; 0253 CartesianDiagramDataCompressor::DataPoint open; 0254 CartesianDiagramDataCompressor::DataPoint close; 0255 CartesianDiagramDataCompressor::DataPoint volume; 0256 0257 if ( d->type == HighLowClose ) { 0258 const CartesianDiagramDataCompressor::CachePosition highPos( row, col * divisor ); 0259 const CartesianDiagramDataCompressor::CachePosition lowPos( row, col * divisor + 1 ); 0260 const CartesianDiagramDataCompressor::CachePosition closePos( row, col * divisor + 2 ); 0261 low = d->compressor.data( lowPos ); 0262 high = d->compressor.data( highPos ); 0263 close = d->compressor.data( closePos ); 0264 } else if ( d->type == OpenHighLowClose || d->type == Candlestick ) { 0265 const CartesianDiagramDataCompressor::CachePosition openPos( row, col * divisor ); 0266 const CartesianDiagramDataCompressor::CachePosition highPos( row, col * divisor + 1 ); 0267 const CartesianDiagramDataCompressor::CachePosition lowPos( row, col * divisor + 2 ); 0268 const CartesianDiagramDataCompressor::CachePosition closePos( row, col * divisor + 3 ); 0269 open = d->compressor.data( openPos ); 0270 low = d->compressor.data( lowPos ); 0271 high = d->compressor.data( highPos ); 0272 close = d->compressor.data( closePos ); 0273 } 0274 0275 0276 switch ( d->type ) { 0277 case HighLowClose: 0278 open.hidden = true; 0279 Q_FALLTHROUGH(); 0280 // Fall-through intended! 0281 case OpenHighLowClose: 0282 if ( close.index.isValid() && low.index.isValid() && high.index.isValid() ) 0283 d->drawOHLCBar( col, open, high, low, close, context ); 0284 break; 0285 case Candlestick: 0286 d->drawCandlestick( col, open, high, low, close, context ); 0287 break; 0288 } 0289 } 0290 } 0291 } 0292 0293 void StockDiagram::resize( const QSizeF &size ) 0294 { 0295 d->compressor.setResolution( static_cast< int >( size.width() * coordinatePlane()->zoomFactorX() ), 0296 static_cast< int >( size.height() * coordinatePlane()->zoomFactorY() ) ); 0297 setDataBoundariesDirty(); 0298 AbstractCartesianDiagram::resize( size ); 0299 } 0300 0301 qreal StockDiagram::threeDItemDepth( int column ) const 0302 { 0303 Q_UNUSED( column ); 0304 //FIXME: Implement threeD functionality 0305 return 1.0; 0306 } 0307 0308 qreal StockDiagram::threeDItemDepth( const QModelIndex &index ) const 0309 { 0310 Q_UNUSED( index ); 0311 //FIXME: Implement threeD functionality 0312 return 1.0; 0313 } 0314 0315 const QPair<QPointF, QPointF> StockDiagram::calculateDataBoundaries() const 0316 { 0317 const int rowCount = attributesModel()->rowCount( attributesModelRootIndex() ); 0318 const int colCount = attributesModel()->columnCount( attributesModelRootIndex() ); 0319 qreal xMin = 0.0; 0320 qreal xMax = rowCount; 0321 qreal yMin = 0.0; 0322 qreal yMax = 0.0; 0323 for ( int row = 0; row < rowCount; row++ ) { 0324 for ( int col = 0; col < colCount; col++ ) { 0325 const CartesianDiagramDataCompressor::CachePosition pos( row, col ); 0326 const CartesianDiagramDataCompressor::DataPoint point = d->compressor.data( pos ); 0327 yMax = qMax( yMax, point.value ); 0328 yMin = qMin( yMin, point.value ); // FIXME: Can stock charts really have negative values? 0329 } 0330 } 0331 return QPair<QPointF, QPointF>( QPointF( xMin, yMin ), QPointF( xMax, yMax ) ); 0332 } 0333