void StockDiagram::Private::drawOHLCBar( int dataset, const CartesianDiagramDataCompressor::DataPoint &open,
        const CartesianDiagramDataCompressor::DataPoint &high,
        const CartesianDiagramDataCompressor::DataPoint &low,
        const CartesianDiagramDataCompressor::DataPoint &close,
        PaintContext *context )
{
    // Note: A row in the model is a column in a StockDiagram
    const int col = low.index.row();

    StockBarAttributes attr = stockDiagram()->stockBarAttributes( col );
    ThreeDBarAttributes threeDAttr = stockDiagram()->threeDBarAttributes( col );
    const qreal tickLength = attr.tickLength();

    const QPointF leftOpenPoint( open.key + 0.5 - tickLength, open.value );
    const QPointF rightOpenPoint( open.key + 0.5, open.value );
    const QPointF highPoint( high.key + 0.5, high.value );
    const QPointF lowPoint( low.key + 0.5, low.value );
    const QPointF leftClosePoint( close.key + 0.5, close.value );
    const QPointF rightClosePoint( close.key + 0.5 + tickLength, close.value );

    bool reversedOrder = false;
    // If 3D mode is enabled, we have to make sure the z-order is right
    if ( threeDAttr.isEnabled() ) {
        const int angle = threeDAttr.angle();
        // Z-order is from right to left
        if ( ( angle >= 0 && angle < 90 ) || ( angle >= 180 && angle < 270 ) )
            reversedOrder = true;
        // Z-order is from left to right
        if ( ( angle >= 90 && angle < 180 ) || ( angle >= 270 && angle < 0 ) )
            reversedOrder = false;
    }

    if ( reversedOrder ) {
        if ( !open.hidden )
            drawLine( dataset, col, leftOpenPoint, rightOpenPoint, context ); // Open marker
        if ( !low.hidden && !high.hidden )
            drawLine( dataset, col, lowPoint, highPoint, context ); // Low-High line
        if ( !close.hidden )
            drawLine( dataset, col, leftClosePoint, rightClosePoint, context ); // Close marker
    } else {
        if ( !close.hidden )
            drawLine( dataset, col, leftClosePoint, rightClosePoint, context ); // Close marker
        if ( !low.hidden && !high.hidden )
            drawLine( dataset, col, lowPoint, highPoint, context ); // Low-High line
        if ( !open.hidden )
            drawLine( dataset, col, leftOpenPoint, rightOpenPoint, context ); // Open marker
    }

    LabelPaintCache lpc;
    if ( !open.hidden ) {
        addLabel( &lpc, diagram->attributesModel()->mapToSource( open.index ), 0,
                            PositionPoints( leftOpenPoint ), Position::South, Position::South, open.value );
    }
    if ( !high.hidden ) {
        addLabel( &lpc, diagram->attributesModel()->mapToSource( high.index ), 0,
                            PositionPoints( highPoint ), Position::South, Position::South, high.value );
    }
    if ( !low.hidden ) {
        addLabel( &lpc, diagram->attributesModel()->mapToSource( low.index ), 0,
                            PositionPoints( lowPoint ), Position::South, Position::South, low.value );
    }
    if ( !close.hidden ) {
        addLabel( &lpc, diagram->attributesModel()->mapToSource( close.index ), 0,
                            PositionPoints( rightClosePoint ), Position::South, Position::South, close.value );
    }
    paintDataValueTextsAndMarkers( context, lpc, false );
}
bool StockBarAttributes::operator==( const StockBarAttributes& r ) const
{
    return candlestickWidth() == r.candlestickWidth() &&
           tickLength() == r.tickLength();
}