KD Chart 2 [rev.2.4]
|
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 00028 using namespace KDChart; 00029 00030 #define d d_func() 00031 00032 StockDiagram::StockDiagram( QWidget *parent, CartesianCoordinatePlane *plane ) 00033 : AbstractCartesianDiagram( new Private(), parent, plane ) 00034 { 00035 init(); 00036 } 00037 00038 StockDiagram::~StockDiagram() 00039 { 00040 } 00041 00045 void StockDiagram::init() 00046 { 00047 d->diagram = this; 00048 d->compressor.setModel( attributesModel() ); 00049 00050 // Set properties to defaults 00051 d->type = HighLowClose; 00052 d->upTrendCandlestickBrush = QBrush( Qt::white ); 00053 d->downTrendCandlestickBrush = QBrush( Qt::black ); 00054 d->upTrendCandlestickPen = QPen( Qt::black ); 00055 d->downTrendCandlestickPen = QPen( Qt::black ); 00056 00057 d->lowHighLinePen = QPen( Qt::black ); 00058 setDatasetDimensionInternal( 3 ); 00059 //setDatasetDimension( 3 ); 00060 00061 setPen( QPen( Qt::black ) ); 00062 } 00063 00068 void StockDiagram::setType( Type type ) 00069 { 00070 d->type = type; 00071 emit propertiesChanged(); 00072 } 00073 00077 StockDiagram::Type StockDiagram::type() const 00078 { 00079 return d->type; 00080 } 00081 00082 void StockDiagram::setStockBarAttributes( const StockBarAttributes &attr ) 00083 { 00084 attributesModel()->setModelData( 00085 qVariantFromValue( attr ), 00086 StockBarAttributesRole ); 00087 emit propertiesChanged(); 00088 } 00089 00090 StockBarAttributes StockDiagram::stockBarAttributes() const 00091 { 00092 return qVariantValue<StockBarAttributes>( 00093 attributesModel()->modelData( StockBarAttributesRole ) ); 00094 } 00095 00096 void StockDiagram::setStockBarAttributes( int column, const StockBarAttributes &attr ) 00097 { 00098 d->setDatasetAttrs( column, qVariantFromValue( attr ), StockBarAttributesRole ); 00099 emit propertiesChanged(); 00100 } 00101 00102 StockBarAttributes StockDiagram::stockBarAttributes( int column ) const 00103 { 00104 const QVariant attr( d->datasetAttrs( column, StockBarAttributesRole ) ); 00105 if ( attr.isValid() ) 00106 return qVariantValue<StockBarAttributes>( attr ); 00107 return stockBarAttributes(); 00108 } 00109 00115 void StockDiagram::setThreeDBarAttributes( const ThreeDBarAttributes &attr ) 00116 { 00117 attributesModel()->setModelData( 00118 qVariantFromValue( attr ), 00119 ThreeDBarAttributesRole ); 00120 emit propertiesChanged(); 00121 } 00122 00128 ThreeDBarAttributes StockDiagram::threeDBarAttributes() const 00129 { 00130 return qVariantValue<ThreeDBarAttributes>( 00131 attributesModel()->modelData( ThreeDBarAttributesRole ) ); 00132 } 00133 00143 void StockDiagram::setThreeDBarAttributes( int column, const ThreeDBarAttributes &attr ) 00144 { 00145 d->setDatasetAttrs( column, qVariantFromValue( attr ), StockBarAttributesRole ); 00146 emit propertiesChanged(); 00147 } 00148 00158 ThreeDBarAttributes StockDiagram::threeDBarAttributes( int column ) const 00159 { 00160 const QVariant attr( d->datasetAttrs( column, ThreeDBarAttributesRole ) ); 00161 if ( attr.isValid() ) 00162 return qVariantValue<ThreeDBarAttributes>( attr ); 00163 return threeDBarAttributes(); 00164 } 00165 00166 00167 void StockDiagram::setLowHighLinePen( const QPen &pen ) 00168 { 00169 d->lowHighLinePen = pen; 00170 } 00171 00172 QPen StockDiagram::lowHighLinePen() const 00173 { 00174 return d->lowHighLinePen; 00175 } 00176 00177 void StockDiagram::setLowHighLinePen( int column, const QPen &pen ) 00178 { 00179 d->lowHighLinePens[column] = pen; 00180 } 00181 00182 QPen StockDiagram::lowHighLinePen( int column ) const 00183 { 00184 if ( d->lowHighLinePens.contains( column ) ) 00185 return d->lowHighLinePens[column]; 00186 return d->lowHighLinePen; 00187 } 00188 00189 void StockDiagram::setUpTrendCandlestickBrush( const QBrush &brush ) 00190 { 00191 d->upTrendCandlestickBrush = brush; 00192 } 00193 00194 QBrush StockDiagram::upTrendCandlestickBrush() const 00195 { 00196 return d->upTrendCandlestickBrush; 00197 } 00198 00199 void StockDiagram::setDownTrendCandlestickBrush( const QBrush &brush ) 00200 { 00201 d->downTrendCandlestickBrush = brush; 00202 } 00203 00204 QBrush StockDiagram::downTrendCandlestickBrush() const 00205 { 00206 return d->downTrendCandlestickBrush; 00207 } 00208 00209 void StockDiagram::setUpTrendCandlestickBrush( int column, const QBrush &brush ) 00210 { 00211 d->upTrendCandlestickBrushes[column] = brush; 00212 } 00213 00214 QBrush StockDiagram::upTrendCandlestickBrush( int column ) const 00215 { 00216 if ( d->upTrendCandlestickBrushes.contains( column ) ) 00217 return d->upTrendCandlestickBrushes[column]; 00218 return d->upTrendCandlestickBrush; 00219 } 00220 00221 void StockDiagram::setDownTrendCandlestickBrush( int column, const QBrush &brush ) 00222 { 00223 d->downTrendCandlestickBrushes[column] = brush; 00224 } 00225 00226 QBrush StockDiagram::downTrendCandlestickBrush( int column ) const 00227 { 00228 if ( d->downTrendCandlestickBrushes.contains( column ) ) 00229 return d->downTrendCandlestickBrushes[column]; 00230 return d->downTrendCandlestickBrush; 00231 } 00232 00233 00234 void StockDiagram::setUpTrendCandlestickPen( const QPen &pen ) 00235 { 00236 d->upTrendCandlestickPen = pen; 00237 } 00238 00239 QPen StockDiagram::upTrendCandlestickPen() const 00240 { 00241 return d->upTrendCandlestickPen; 00242 } 00243 00244 void StockDiagram::setDownTrendCandlestickPen( const QPen &pen ) 00245 { 00246 d->downTrendCandlestickPen = pen; 00247 } 00248 00249 QPen StockDiagram::downTrendCandlestickPen() const 00250 { 00251 return d->downTrendCandlestickPen; 00252 } 00253 00254 void StockDiagram::setUpTrendCandlestickPen( int column, const QPen &pen ) 00255 { 00256 d->upTrendCandlestickPens[column] = pen; 00257 } 00258 00259 QPen StockDiagram::upTrendCandlestickPen( int column ) const 00260 { 00261 if ( d->upTrendCandlestickPens.contains( column ) ) 00262 return d->upTrendCandlestickPens[column]; 00263 return d->upTrendCandlestickPen; 00264 } 00265 00266 void StockDiagram::setDownTrendCandlestickPen( int column, const QPen &pen ) 00267 { 00268 d->downTrendCandlestickPens[column] = pen; 00269 } 00270 00271 QPen StockDiagram::downTrendCandlestickPen( int column ) const 00272 { 00273 if ( d->downTrendCandlestickPens.contains( column ) ) 00274 return d->downTrendCandlestickPens[column]; 00275 return d->downTrendCandlestickPen; 00276 } 00277 00278 #if QT_VERSION < 0x040400 || defined(Q_COMPILER_MANGLES_RETURN_TYPE) 00279 const 00280 #endif 00281 int StockDiagram::numberOfAbscissaSegments() const { return 1; } 00282 00283 #if QT_VERSION < 0x040400 || defined(Q_COMPILER_MANGLES_RETURN_TYPE) 00284 const 00285 #endif 00286 int StockDiagram::numberOfOrdinateSegments() const { return 1; } 00287 00288 void StockDiagram::paint( PaintContext *context ) 00289 { 00290 // Clear old reverse mapping data and create new 00291 // reverse mapping scene 00292 d->reverseMapper.clear(); 00293 00294 PainterSaver painterSaver( context->painter() ); 00295 const int rowCount = attributesModel()->rowCount( attributesModelRootIndex() ); 00296 const int divisor = ( d->type == OpenHighLowClose || d->type == Candlestick ) ? 4 : 3; 00297 const int colCount = attributesModel()->columnCount( attributesModelRootIndex() ) / divisor; 00298 for ( int col = 0; col < colCount; ++col ) 00299 { 00300 for ( int row = 0; row < rowCount; row++ ) { 00301 CartesianDiagramDataCompressor::DataPoint low; 00302 CartesianDiagramDataCompressor::DataPoint high; 00303 CartesianDiagramDataCompressor::DataPoint open; 00304 CartesianDiagramDataCompressor::DataPoint close; 00305 CartesianDiagramDataCompressor::DataPoint volume; 00306 00307 if ( d->type == HighLowClose ) { 00308 const CartesianDiagramDataCompressor::CachePosition highPos( row, col * divisor ); 00309 const CartesianDiagramDataCompressor::CachePosition lowPos( row, col * divisor + 1 ); 00310 const CartesianDiagramDataCompressor::CachePosition closePos( row, col * divisor + 2 ); 00311 low = d->compressor.data( lowPos ); 00312 high = d->compressor.data( highPos ); 00313 close = d->compressor.data( closePos ); 00314 } else if ( d->type == OpenHighLowClose || d->type == Candlestick ) { 00315 const CartesianDiagramDataCompressor::CachePosition openPos( row, col * divisor ); 00316 const CartesianDiagramDataCompressor::CachePosition highPos( row, col * divisor + 1 ); 00317 const CartesianDiagramDataCompressor::CachePosition lowPos( row, col * divisor + 2 ); 00318 const CartesianDiagramDataCompressor::CachePosition closePos( row, col * divisor + 3 ); 00319 open = d->compressor.data( openPos ); 00320 low = d->compressor.data( lowPos ); 00321 high = d->compressor.data( highPos ); 00322 close = d->compressor.data( closePos ); 00323 } 00324 00325 00326 switch( d->type ) { 00327 case HighLowClose: 00328 open.hidden = true; 00329 // Fall-through intended! 00330 case OpenHighLowClose: 00331 if ( close.index.isValid() && low.index.isValid() && high.index.isValid() ) 00332 d->drawOHLCBar( col, open, high, low, close, context ); 00333 break; 00334 case Candlestick: 00335 d->drawCandlestick( col, open, high, low, close, context ); 00336 break; 00337 } 00338 } 00339 } 00340 } 00341 00342 void StockDiagram::resize( const QSizeF &size ) 00343 { 00344 d->compressor.setResolution( static_cast< int >( size.width() * coordinatePlane()->zoomFactorX() ), 00345 static_cast< int >( size.height() * coordinatePlane()->zoomFactorY() ) ); 00346 setDataBoundariesDirty(); 00347 } 00348 00349 double StockDiagram::threeDItemDepth( int column ) const 00350 { 00351 Q_UNUSED( column ); 00352 //FIXME: Implement threeD functionality 00353 return 1.0; 00354 } 00355 00356 double StockDiagram::threeDItemDepth( const QModelIndex &index ) const 00357 { 00358 Q_UNUSED( index ); 00359 //FIXME: Implement threeD functionality 00360 return 1.0; 00361 } 00362 00363 const QPair<QPointF, QPointF> StockDiagram::calculateDataBoundaries() const 00364 { 00365 const int rowCount = attributesModel()->rowCount( attributesModelRootIndex() ); 00366 const int colCount = attributesModel()->columnCount( attributesModelRootIndex() ); 00367 qreal xMin = 0.0; 00368 qreal xMax = rowCount; 00369 qreal yMin = 0.0; 00370 qreal yMax = 0.0; 00371 for ( int row = 0; row < rowCount; row++ ) { 00372 for ( int col = 0; col < colCount; col++ ) { 00373 const CartesianDiagramDataCompressor::CachePosition pos( row, col ); 00374 const CartesianDiagramDataCompressor::DataPoint point = d->compressor.data( pos ); 00375 yMax = qMax( yMax, point.value ); 00376 yMin = qMin( yMin, point.value ); // FIXME: Can stock charts really have negative values? 00377 } 00378 } 00379 return QPair<QPointF, QPointF>( QPointF( xMin, yMin ), QPointF( xMax, yMax ) ); 00380 } 00381