# KDChartBarDiagram_p.cpp

Go to the documentation of this file.

    00001 /* -*- Mode: C++ -*-
    00002    KDChart - a multi-platform charting engine
    00003    */
    00004
    00005 /****************************************************************************
    00006  ** Copyright (C) 2005-2007 Klarälvdalens Datakonsult AB.  All rights reserved.
    00007  **
    00008  ** This file is part of the KD Chart library.
    00009  **
    00010  ** This file may be distributed and/or modified under the terms of the
    00011  ** GNU General Public License version 2 as published by the Free Software
    00012  ** Foundation and appearing in the file LICENSE.GPL included in the
    00013  ** packaging of this file.
    00014  **
    00015  ** Licensees holding valid commercial KD Chart licenses may use this file in
    00016  ** accordance with the KD Chart Commercial License Agreement provided with
    00017  ** the Software.
    00018  **
    00019  ** This file is provided AS IS with NO WARRANTY OF ANY KIND, INCLUDING THE
    00020  ** WARRANTY OF DESIGN, MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
    00021  **
    00022  ** See http://www.kdab.net/kdchart for
    00023  **   information about KD Chart Commercial License Agreements.
    00024  **
    00025  ** Contact info@kdab.net if any conditions of this
    00026  ** licensing are not clear to you.
    00027  **
    00028  **********************************************************************/
    00029
    00030 #include "KDChartBarDiagram.h"
    00031 #include "KDChartDataValueAttributes.h"
    00032
    00033 #include "KDChartBarDiagram_p.h"
    00034
    00035 using namespace KDChart;
    00036
    00037 BarDiagram::Private::Private( const Private& rhs )
    00038     : AbstractCartesianDiagram::Private( rhs )
    00039 {
    00040 }
    00041
    00042 void BarDiagram::BarDiagramType::paintBars( PaintContext* ctx, const QModelIndex& index, const QRectF& bar, double& maxDepth )
    00043 {
    00044     QRectF isoRect;
    00045     QPolygonF topPoints, sidePoints;
    00046     ThreeDBarAttributes threeDAttrs = diagram()->threeDBarAttributes( index );
    00047     double usedDepth;
    00048
    00049     //Pending Michel: configure threeDBrush settings - shadowColor etc...
    00050     QBrush indexBrush ( diagram()->brush( index ) );
    00051     QPen indexPen( diagram()->pen( index ) );
    00052     PainterSaver painterSaver( ctx->painter() );
    00053     if ( diagram()->antiAliasing() )
    00054         ctx->painter()->setRenderHint ( QPainter::Antialiasing );
    00055     ctx->painter()->setBrush( indexBrush );
    00056     ctx->painter()->setPen( indexPen );
    00057     if ( threeDAttrs.isEnabled() ) {
    00058         bool stackedMode = false;
    00059         bool percentMode = false;
    00060         bool paintTop = true;
    00061         if ( maxDepth )
    00062             threeDAttrs.setDepth( -maxDepth );
    00063         QPointF boundRight =  ctx->coordinatePlane()->translate( diagram()->dataBoundaries().second );
    00064         //fixme adjust the painting to reasonable depth value
    00065         switch ( type() )
    00066         {
    00067         case BarDiagram::Normal:
    00068             usedDepth = threeDAttrs.depth()/4;
    00069             stackedMode = false;
    00070             percentMode = false;
    00071             break;
    00072         case BarDiagram::Stacked:
    00073             usedDepth = threeDAttrs.depth();
    00074             stackedMode = true;
    00075             percentMode = false;
    00076             break;
    00077         case BarDiagram::Percent:
    00078             usedDepth = threeDAttrs.depth();
    00079             stackedMode = false;
    00080             percentMode = true;
    00081             break;
    00082         default:
    00083             Q_ASSERT_X ( false, "dataBoundaries()",
    00084                          "Type item does not match a defined bar chart Type." );
    00085         }
    00086         isoRect = bar.translated( usedDepth, -usedDepth );
    00087         // we need to find out if the height is negative
    00088         // and in this case paint it up and down
    00089         //qDebug() << isoRect.height();
    00090         if (  isoRect.height() < 0 ) {
    00091           topPoints << isoRect.bottomLeft() << isoRect.bottomRight()
    00092                     << bar.bottomRight() << bar.bottomLeft();
    00093           if ( stackedMode ) {
    00094               // fix it when several negative stacked values
    00095               if (  index.column() == 0 ) {
    00096                   paintTop = true;
    00097               }
    00098               else
    00099                   paintTop = false;
    00100           }
    00101
    00102         } else {
    00103             reverseMapper().addRect( index.row(), index.column(), isoRect );
    00104             ctx->painter()->drawRect( isoRect );
    00105             topPoints << bar.topLeft() << bar.topRight() << isoRect.topRight() << isoRect.topLeft();
    00106         }
    00107
    00108         if ( percentMode && isoRect.height() == 0 )
    00109             paintTop = false;
    00110
    00111         bool needToSetClippingOffForTop = false;
    00112         if ( paintTop ){
    00113             // Draw the top, if at least one of the top's points is
    00114             // either inside or near at the edge of the coordinate plane:
    00115             bool drawIt = false;
    00116             bool hasPointOutside = false;
    00117             const QRectF r( ctx->rectangle().adjusted(0,-1,1,0) );
    00118             KDAB_FOREACH( QPointF pt, topPoints ) {
    00119                 if( r.contains( pt ) )
    00120                     drawIt = true;
    00121                 else
    00122                     hasPointOutside = true;
    00123             }
    00124             if( drawIt ){
    00125                 const PainterSaver p( ctx->painter() );
    00126                 needToSetClippingOffForTop = hasPointOutside && ctx->painter()->hasClipping();
    00127                 if( needToSetClippingOffForTop )
    00128                     ctx->painter()->setClipping( false );
    00129                 reverseMapper().addPolygon( index.row(), index.column(), topPoints );
    00130                 ctx->painter()->drawPolygon( topPoints );
    00131             }
    00132         }
    00133
    00134
    00135
    00136         sidePoints << bar.topRight() << isoRect.topRight() << isoRect.bottomRight() << bar.bottomRight();
    00137         if (  bar.height() != 0 ){
    00138             const PainterSaver p( ctx->painter() );
    00139             if( needToSetClippingOffForTop )
    00140                 ctx->painter()->setClipping( false );
    00141             reverseMapper().addPolygon( index.row(), index.column(), sidePoints );
    00142             ctx->painter()->drawPolygon( sidePoints );
    00143         }
    00144     }
    00145
    00146     if( bar.height() != 0 )
    00147     {
    00148         reverseMapper().addRect( index.row(), index.column(), bar );
    00149         ctx->painter()->drawRect( bar );
    00150     }
    00151     // reset
    00152     //diagram()->maxDepth = threeDAttrs.depth();
    00153 }
    00154
    00155 AttributesModel* BarDiagram::BarDiagramType::attributesModel() const
    00156 {
    00157     return m_private->attributesModel;
    00158 }
    00159
    00160 QModelIndex BarDiagram::BarDiagramType::attributesModelRootIndex() const
    00161 {
    00162     return m_private->diagram->attributesModelRootIndex();
    00163 }
    00164
    00165 BarDiagram* BarDiagram::BarDiagramType::diagram() const
    00166 {
    00167     return m_private->diagram;
    00168 }
    00169
    00170 void BarDiagram::BarDiagramType::appendDataValueTextInfoToList(
    00171             AbstractDiagram * diagram,
    00172             DataValueTextInfoList & list,
    00173             const QModelIndex & index,
    00174             const PositionPoints& points,
    00175             const Position& autoPositionPositive,
    00176             const Position& autoPositionNegative,
    00177             const qreal value )
    00178 {
    00179     m_private->appendDataValueTextInfoToList( diagram, list, index, points,
    00180                                               autoPositionPositive, autoPositionNegative, value );
    00181 }
    00182
    00183 void BarDiagram::BarDiagramType::paintDataValueTextsAndMarkers(
    00184     AbstractDiagram* diagram,
    00185     PaintContext* ctx,
    00186     const DataValueTextInfoList & list,
    00187     bool paintMarkers )
    00188 {
    00189     m_private->paintDataValueTextsAndMarkers( diagram, ctx, list, paintMarkers );
    00190 }
    00191
    00192
    00193 void BarDiagram::BarDiagramType::calculateValueAndGapWidths( int rowCount,int colCount,
    00194                                              double groupWidth,
    00195                                              double& outBarWidth,
    00196                                              double& outSpaceBetweenBars,
    00197                                              double& outSpaceBetweenGroups )
    00198 {
    00199
    00200     Q_UNUSED( rowCount );
    00201
    00202     BarAttributes ba = diagram()->barAttributes( diagram()->model()->index( 0, 0, diagram()->rootIndex() ) );
    00203
    00204     // Pending Michel Fixme
    00205     /* We are colCount groups to paint. Each group is centered around the
    00206      * horizontal point position on the grid. The full area covers the
    00207      * values -1 to colCount + 1. A bar has a relative width of one unit,
    00208      * the gaps between bars are 0.5 wide, and the gap between groups is
    00209      * also one unit, by default. */
    00210
    00211     double units;
    00212     if( type() == Normal )
    00213         units = colCount // number of bars in group * 1.0
    00214                 + (colCount-1) * ba.barGapFactor() // number of bar gaps
    00215                 + 1 * ba.groupGapFactor(); // number of group gaps
    00216     else
    00217         units = 1 + 1 * ba.groupGapFactor();
    00218
    00219     double unitWidth = groupWidth / units;
    00220     outBarWidth = unitWidth;
    00221     outSpaceBetweenBars += unitWidth * ba.barGapFactor();
    00222     // Pending Michel - minLimit: allow space between bars to be reduced until the bars are displayed next to each other.
    00223     // is that what we want?
    00224     if ( outSpaceBetweenBars < 0 )
    00225         outSpaceBetweenBars = 0;
    00226
    00227     outSpaceBetweenGroups += unitWidth * ba.groupGapFactor();
    00228 }
    00229
    00230 ReverseMapper& BarDiagram::BarDiagramType::reverseMapper()
    00231 {
    00232     return m_private->reverseMapper;
    00233 }
    00234
    00235 CartesianDiagramDataCompressor& BarDiagram::BarDiagramType::compressor() const
    00236 {
    00237     return m_private->compressor;
    00238 }