KD Chart 2
[rev.2.5]
|
00001 /**************************************************************************** 00002 ** Copyright (C) 2001-2012 Klaralvdalens Datakonsult AB. All rights reserved. 00003 ** 00004 ** This file is part of the KD Chart library. 00005 ** 00006 ** Licensees holding valid commercial KD Chart licenses may use this file in 00007 ** accordance with the KD Chart Commercial License Agreement provided with 00008 ** the Software. 00009 ** 00010 ** 00011 ** This file may be distributed and/or modified under the terms of the 00012 ** GNU General Public License version 2 and version 3 as published by the 00013 ** Free Software Foundation and appearing in the file LICENSE.GPL.txt included. 00014 ** 00015 ** This file is provided AS IS with NO WARRANTY OF ANY KIND, INCLUDING THE 00016 ** WARRANTY OF DESIGN, MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. 00017 ** 00018 ** Contact info@kdab.com if any conditions of this licensing are not 00019 ** clear to you. 00020 ** 00021 **********************************************************************/ 00022 00023 #include "KDChartStockDiagram.h" 00024 #include "KDChartStockDiagram_p.h" 00025 00026 #include "KDChartPaintContext.h" 00027 #include "KDChartPainterSaver_p.h" 00028 00029 using namespace KDChart; 00030 00031 #define d d_func() 00032 00033 StockDiagram::StockDiagram( QWidget *parent, CartesianCoordinatePlane *plane ) 00034 : AbstractCartesianDiagram( new Private(), parent, plane ) 00035 { 00036 init(); 00037 } 00038 00039 StockDiagram::~StockDiagram() 00040 { 00041 } 00042 00046 void StockDiagram::init() 00047 { 00048 d->diagram = this; 00049 d->compressor.setModel( attributesModel() ); 00050 00051 // Set properties to defaults 00052 d->type = HighLowClose; 00053 d->upTrendCandlestickBrush = QBrush( Qt::white ); 00054 d->downTrendCandlestickBrush = QBrush( Qt::black ); 00055 d->upTrendCandlestickPen = QPen( Qt::black ); 00056 d->downTrendCandlestickPen = QPen( Qt::black ); 00057 00058 d->lowHighLinePen = QPen( Qt::black ); 00059 setDatasetDimensionInternal( 3 ); 00060 //setDatasetDimension( 3 ); 00061 00062 setPen( QPen( Qt::black ) ); 00063 } 00064 00069 void StockDiagram::setType( Type type ) 00070 { 00071 d->type = type; 00072 emit propertiesChanged(); 00073 } 00074 00078 StockDiagram::Type StockDiagram::type() const 00079 { 00080 return d->type; 00081 } 00082 00083 void StockDiagram::setStockBarAttributes( const StockBarAttributes &attr ) 00084 { 00085 attributesModel()->setModelData( 00086 qVariantFromValue( attr ), 00087 StockBarAttributesRole ); 00088 emit propertiesChanged(); 00089 } 00090 00091 StockBarAttributes StockDiagram::stockBarAttributes() const 00092 { 00093 return qVariantValue<StockBarAttributes>( 00094 attributesModel()->modelData( StockBarAttributesRole ) ); 00095 } 00096 00097 void StockDiagram::setStockBarAttributes( int column, const StockBarAttributes &attr ) 00098 { 00099 d->setDatasetAttrs( column, qVariantFromValue( attr ), StockBarAttributesRole ); 00100 emit propertiesChanged(); 00101 } 00102 00103 StockBarAttributes StockDiagram::stockBarAttributes( int column ) const 00104 { 00105 const QVariant attr( d->datasetAttrs( column, StockBarAttributesRole ) ); 00106 if ( attr.isValid() ) 00107 return qVariantValue<StockBarAttributes>( attr ); 00108 return stockBarAttributes(); 00109 } 00110 00116 void StockDiagram::setThreeDBarAttributes( const ThreeDBarAttributes &attr ) 00117 { 00118 attributesModel()->setModelData( 00119 qVariantFromValue( attr ), 00120 ThreeDBarAttributesRole ); 00121 emit propertiesChanged(); 00122 } 00123 00129 ThreeDBarAttributes StockDiagram::threeDBarAttributes() const 00130 { 00131 return qVariantValue<ThreeDBarAttributes>( 00132 attributesModel()->modelData( ThreeDBarAttributesRole ) ); 00133 } 00134 00144 void StockDiagram::setThreeDBarAttributes( int column, const ThreeDBarAttributes &attr ) 00145 { 00146 d->setDatasetAttrs( column, qVariantFromValue( attr ), StockBarAttributesRole ); 00147 emit propertiesChanged(); 00148 } 00149 00159 ThreeDBarAttributes StockDiagram::threeDBarAttributes( int column ) const 00160 { 00161 const QVariant attr( d->datasetAttrs( column, ThreeDBarAttributesRole ) ); 00162 if ( attr.isValid() ) 00163 return qVariantValue<ThreeDBarAttributes>( attr ); 00164 return threeDBarAttributes(); 00165 } 00166 00167 00168 void StockDiagram::setLowHighLinePen( const QPen &pen ) 00169 { 00170 d->lowHighLinePen = pen; 00171 } 00172 00173 QPen StockDiagram::lowHighLinePen() const 00174 { 00175 return d->lowHighLinePen; 00176 } 00177 00178 void StockDiagram::setLowHighLinePen( int column, const QPen &pen ) 00179 { 00180 d->lowHighLinePens[column] = pen; 00181 } 00182 00183 QPen StockDiagram::lowHighLinePen( int column ) const 00184 { 00185 if ( d->lowHighLinePens.contains( column ) ) 00186 return d->lowHighLinePens[column]; 00187 return d->lowHighLinePen; 00188 } 00189 00190 void StockDiagram::setUpTrendCandlestickBrush( const QBrush &brush ) 00191 { 00192 d->upTrendCandlestickBrush = brush; 00193 } 00194 00195 QBrush StockDiagram::upTrendCandlestickBrush() const 00196 { 00197 return d->upTrendCandlestickBrush; 00198 } 00199 00200 void StockDiagram::setDownTrendCandlestickBrush( const QBrush &brush ) 00201 { 00202 d->downTrendCandlestickBrush = brush; 00203 } 00204 00205 QBrush StockDiagram::downTrendCandlestickBrush() const 00206 { 00207 return d->downTrendCandlestickBrush; 00208 } 00209 00210 void StockDiagram::setUpTrendCandlestickBrush( int column, const QBrush &brush ) 00211 { 00212 d->upTrendCandlestickBrushes[column] = brush; 00213 } 00214 00215 QBrush StockDiagram::upTrendCandlestickBrush( int column ) const 00216 { 00217 if ( d->upTrendCandlestickBrushes.contains( column ) ) 00218 return d->upTrendCandlestickBrushes[column]; 00219 return d->upTrendCandlestickBrush; 00220 } 00221 00222 void StockDiagram::setDownTrendCandlestickBrush( int column, const QBrush &brush ) 00223 { 00224 d->downTrendCandlestickBrushes[column] = brush; 00225 } 00226 00227 QBrush StockDiagram::downTrendCandlestickBrush( int column ) const 00228 { 00229 if ( d->downTrendCandlestickBrushes.contains( column ) ) 00230 return d->downTrendCandlestickBrushes[column]; 00231 return d->downTrendCandlestickBrush; 00232 } 00233 00234 00235 void StockDiagram::setUpTrendCandlestickPen( const QPen &pen ) 00236 { 00237 d->upTrendCandlestickPen = pen; 00238 } 00239 00240 QPen StockDiagram::upTrendCandlestickPen() const 00241 { 00242 return d->upTrendCandlestickPen; 00243 } 00244 00245 void StockDiagram::setDownTrendCandlestickPen( const QPen &pen ) 00246 { 00247 d->downTrendCandlestickPen = pen; 00248 } 00249 00250 QPen StockDiagram::downTrendCandlestickPen() const 00251 { 00252 return d->downTrendCandlestickPen; 00253 } 00254 00255 void StockDiagram::setUpTrendCandlestickPen( int column, const QPen &pen ) 00256 { 00257 d->upTrendCandlestickPens[column] = pen; 00258 } 00259 00260 QPen StockDiagram::upTrendCandlestickPen( int column ) const 00261 { 00262 if ( d->upTrendCandlestickPens.contains( column ) ) 00263 return d->upTrendCandlestickPens[column]; 00264 return d->upTrendCandlestickPen; 00265 } 00266 00267 void StockDiagram::setDownTrendCandlestickPen( int column, const QPen &pen ) 00268 { 00269 d->downTrendCandlestickPens[column] = pen; 00270 } 00271 00272 QPen StockDiagram::downTrendCandlestickPen( int column ) const 00273 { 00274 if ( d->downTrendCandlestickPens.contains( column ) ) 00275 return d->downTrendCandlestickPens[column]; 00276 return d->downTrendCandlestickPen; 00277 } 00278 00279 #if QT_VERSION < 0x040400 || defined(Q_COMPILER_MANGLES_RETURN_TYPE) 00280 const 00281 #endif 00282 int StockDiagram::numberOfAbscissaSegments() const { return 1; } 00283 00284 #if QT_VERSION < 0x040400 || defined(Q_COMPILER_MANGLES_RETURN_TYPE) 00285 const 00286 #endif 00287 int StockDiagram::numberOfOrdinateSegments() const { return 1; } 00288 00289 void StockDiagram::paint( PaintContext *context ) 00290 { 00291 // Clear old reverse mapping data and create new 00292 // reverse mapping scene 00293 d->reverseMapper.clear(); 00294 00295 PainterSaver painterSaver( context->painter() ); 00296 const int rowCount = attributesModel()->rowCount( attributesModelRootIndex() ); 00297 const int divisor = ( d->type == OpenHighLowClose || d->type == Candlestick ) ? 4 : 3; 00298 const int colCount = attributesModel()->columnCount( attributesModelRootIndex() ) / divisor; 00299 for ( int col = 0; col < colCount; ++col ) 00300 { 00301 for ( int row = 0; row < rowCount; row++ ) { 00302 CartesianDiagramDataCompressor::DataPoint low; 00303 CartesianDiagramDataCompressor::DataPoint high; 00304 CartesianDiagramDataCompressor::DataPoint open; 00305 CartesianDiagramDataCompressor::DataPoint close; 00306 CartesianDiagramDataCompressor::DataPoint volume; 00307 00308 if ( d->type == HighLowClose ) { 00309 const CartesianDiagramDataCompressor::CachePosition highPos( row, col * divisor ); 00310 const CartesianDiagramDataCompressor::CachePosition lowPos( row, col * divisor + 1 ); 00311 const CartesianDiagramDataCompressor::CachePosition closePos( row, col * divisor + 2 ); 00312 low = d->compressor.data( lowPos ); 00313 high = d->compressor.data( highPos ); 00314 close = d->compressor.data( closePos ); 00315 } else if ( d->type == OpenHighLowClose || d->type == Candlestick ) { 00316 const CartesianDiagramDataCompressor::CachePosition openPos( row, col * divisor ); 00317 const CartesianDiagramDataCompressor::CachePosition highPos( row, col * divisor + 1 ); 00318 const CartesianDiagramDataCompressor::CachePosition lowPos( row, col * divisor + 2 ); 00319 const CartesianDiagramDataCompressor::CachePosition closePos( row, col * divisor + 3 ); 00320 open = d->compressor.data( openPos ); 00321 low = d->compressor.data( lowPos ); 00322 high = d->compressor.data( highPos ); 00323 close = d->compressor.data( closePos ); 00324 } 00325 00326 00327 switch( d->type ) { 00328 case HighLowClose: 00329 open.hidden = true; 00330 // Fall-through intended! 00331 case OpenHighLowClose: 00332 if ( close.index.isValid() && low.index.isValid() && high.index.isValid() ) 00333 d->drawOHLCBar( col, open, high, low, close, context ); 00334 break; 00335 case Candlestick: 00336 d->drawCandlestick( col, open, high, low, close, context ); 00337 break; 00338 } 00339 } 00340 } 00341 } 00342 00343 void StockDiagram::resize( const QSizeF &size ) 00344 { 00345 d->compressor.setResolution( static_cast< int >( size.width() * coordinatePlane()->zoomFactorX() ), 00346 static_cast< int >( size.height() * coordinatePlane()->zoomFactorY() ) ); 00347 setDataBoundariesDirty(); 00348 } 00349 00350 qreal StockDiagram::threeDItemDepth( int column ) const 00351 { 00352 Q_UNUSED( column ); 00353 //FIXME: Implement threeD functionality 00354 return 1.0; 00355 } 00356 00357 qreal StockDiagram::threeDItemDepth( const QModelIndex &index ) const 00358 { 00359 Q_UNUSED( index ); 00360 //FIXME: Implement threeD functionality 00361 return 1.0; 00362 } 00363 00364 const QPair<QPointF, QPointF> StockDiagram::calculateDataBoundaries() const 00365 { 00366 const int rowCount = attributesModel()->rowCount( attributesModelRootIndex() ); 00367 const int colCount = attributesModel()->columnCount( attributesModelRootIndex() ); 00368 qreal xMin = 0.0; 00369 qreal xMax = rowCount; 00370 qreal yMin = 0.0; 00371 qreal yMax = 0.0; 00372 for ( int row = 0; row < rowCount; row++ ) { 00373 for ( int col = 0; col < colCount; col++ ) { 00374 const CartesianDiagramDataCompressor::CachePosition pos( row, col ); 00375 const CartesianDiagramDataCompressor::DataPoint point = d->compressor.data( pos ); 00376 yMax = qMax( yMax, point.value ); 00377 yMin = qMin( yMin, point.value ); // FIXME: Can stock charts really have negative values? 00378 } 00379 } 00380 return QPair<QPointF, QPointF>( QPointF( xMin, yMin ), QPointF( xMax, yMax ) ); 00381 } 00382