~ubuntu-branches/ubuntu/precise/koffice/precise

« back to all changes in this revision

Viewing changes to plugins/chartshape/kdchart/src/KDChartRingDiagram.cpp

  • Committer: Bazaar Package Importer
  • Author(s): Alessandro Ghersi
  • Date: 2010-10-27 17:52:57 UTC
  • mfrom: (0.12.1 upstream)
  • Revision ID: james.westby@ubuntu.com-20101027175257-s04zqqk5bs8ckm9o
Tags: 1:2.2.83-0ubuntu1
* Merge with Debian git remaining changes:
 - Add build-deps on librcps-dev, opengtl-dev, libqtgtl-dev, freetds-dev,
   create-resources, libspnav-dev
 - Remove needless build-dep on libwv2-dev
 - koffice-libs recommends create-resources
 - krita recommends pstoedit
 - Keep our patches
* New upstream release 2.3 beta 3
  - Remove debian/patches fixed by upstream
  - Update install files

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
/****************************************************************************
 
2
** Copyright (C) 2001-2010 Klaralvdalens Datakonsult AB.  All rights reserved.
 
3
**
 
4
** This file is part of the KD Chart library.
 
5
**
 
6
** Licensees holding valid commercial KD Chart licenses may use this file in
 
7
** accordance with the KD Chart Commercial License Agreement provided with
 
8
** the Software.
 
9
**
 
10
**
 
11
** This file may be distributed and/or modified under the terms of the
 
12
** GNU General Public License version 2 and version 3 as published by the
 
13
** Free Software Foundation and appearing in the file LICENSE.GPL included.
 
14
**
 
15
** This file is provided AS IS with NO WARRANTY OF ANY KIND, INCLUDING THE
 
16
** WARRANTY OF DESIGN, MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
 
17
**
 
18
** Contact info@kdab.com if any conditions of this licensing are not
 
19
** clear to you.
 
20
**
 
21
**********************************************************************/
 
22
 
 
23
#include "KDChartRingDiagram.h"
 
24
#include "KDChartRingDiagram_p.h"
 
25
 
 
26
#include "KDChartAttributesModel.h"
 
27
#include "KDChartPaintContext.h"
 
28
#include "KDChartPainterSaver_p.h"
 
29
#include "KDChartPieAttributes.h"
 
30
#include "KDChartDataValueAttributes.h"
 
31
 
 
32
#include <QPainter>
 
33
 
 
34
#include <KDABLibFakes>
 
35
 
 
36
using namespace KDChart;
 
37
 
 
38
RingDiagram::Private::Private()
 
39
    : relativeThickness( false )
 
40
    , expandWhenExploded( false )
 
41
{
 
42
}
 
43
 
 
44
RingDiagram::Private::~Private() {}
 
45
 
 
46
#define d d_func()
 
47
 
 
48
RingDiagram::RingDiagram( QWidget* parent, PolarCoordinatePlane* plane ) :
 
49
    AbstractPieDiagram( new Private(), parent, plane )
 
50
{
 
51
    init();
 
52
}
 
53
 
 
54
RingDiagram::~RingDiagram()
 
55
{
 
56
}
 
57
 
 
58
void RingDiagram::init()
 
59
{
 
60
}
 
61
 
 
62
/**
 
63
  * Creates an exact copy of this diagram.
 
64
  */
 
65
RingDiagram * RingDiagram::clone() const
 
66
{
 
67
    return new RingDiagram( new Private( *d ) );
 
68
}
 
69
 
 
70
bool RingDiagram::compare( const RingDiagram* other )const
 
71
{
 
72
    if( other == this ) return true;
 
73
    if( ! other ){
 
74
        return false;
 
75
    }
 
76
    /*
 
77
    qDebug() <<"\n             RingDiagram::compare():";
 
78
            // compare own properties
 
79
    qDebug() << (type() == other->type());
 
80
    qDebug() << (relativeThickness()  == other->relativeThickness());
 
81
    qDebug() << (expandWhenExploded() == other->expandWhenExploded());
 
82
    */
 
83
    return  // compare the base class
 
84
            ( static_cast<const AbstractPieDiagram*>(this)->compare( other ) ) &&
 
85
            // compare own properties
 
86
            (relativeThickness()  == other->relativeThickness()) &&
 
87
            (expandWhenExploded() == other->expandWhenExploded());
 
88
}
 
89
 
 
90
void RingDiagram::setRelativeThickness( bool relativeThickness )
 
91
{
 
92
    d->relativeThickness = relativeThickness;
 
93
}
 
94
 
 
95
bool RingDiagram::relativeThickness() const
 
96
{
 
97
    return d->relativeThickness;
 
98
}
 
99
 
 
100
void RingDiagram::setExpandWhenExploded( bool expand )
 
101
{
 
102
        d->expandWhenExploded = expand;
 
103
}
 
104
 
 
105
bool RingDiagram::expandWhenExploded() const
 
106
{
 
107
        return d->expandWhenExploded;
 
108
}
 
109
 
 
110
const QPair<QPointF, QPointF> RingDiagram::calculateDataBoundaries () const
 
111
{
 
112
    if ( !checkInvariants( true ) ) return QPair<QPointF, QPointF>( QPointF( 0, 0 ), QPointF( 0, 0 ) );
 
113
 
 
114
    const PieAttributes attrs( pieAttributes( model()->index( 0, 0, rootIndex() ) ) );
 
115
 
 
116
    QPointF bottomLeft ( QPointF( 0, 0 ) );
 
117
    QPointF topRight;
 
118
    // If we explode, we need extra space for the pie slice that has
 
119
    // the largest explosion distance.
 
120
    if ( attrs.explode() ) {
 
121
        const int rCount = rowCount();
 
122
        const int colCount = columnCount();
 
123
        qreal maxExplode = 0.0;
 
124
        for( int i = 0; i < rCount; ++i ){
 
125
                qreal maxExplodeInThisRow = 0.0;
 
126
                for( int j = 0; j < colCount; ++j ){
 
127
                        const PieAttributes columnAttrs( pieAttributes( model()->index( i, j, rootIndex() ) ) );
 
128
                        //qDebug() << columnAttrs.explodeFactor();
 
129
                        maxExplodeInThisRow = qMax( maxExplodeInThisRow, columnAttrs.explodeFactor() );
 
130
                }
 
131
                maxExplode += maxExplodeInThisRow;
 
132
 
 
133
                // FIXME: What if explode factor of inner ring is > 1.0 ?
 
134
                if ( !d->expandWhenExploded )
 
135
                        break;
 
136
        }
 
137
        // explode factor is relative to width (outer r - inner r) of one ring
 
138
        maxExplode /= ( rCount + 1);
 
139
        topRight = QPointF( 1.0+maxExplode, 1.0+maxExplode );
 
140
    }else{
 
141
        topRight = QPointF( 1.0, 1.0 );
 
142
    }
 
143
    return QPair<QPointF, QPointF> ( bottomLeft,  topRight );
 
144
}
 
145
 
 
146
void RingDiagram::paintEvent( QPaintEvent* )
 
147
{
 
148
    QPainter painter ( viewport() );
 
149
    PaintContext ctx;
 
150
    ctx.setPainter ( &painter );
 
151
    ctx.setRectangle( QRectF ( 0, 0, width(), height() ) );
 
152
    paint ( &ctx );
 
153
}
 
154
 
 
155
void RingDiagram::resizeEvent( QResizeEvent* )
 
156
{
 
157
}
 
158
 
 
159
static QRectF buildReferenceRect( const PolarCoordinatePlane* plane )
 
160
{
 
161
    QRectF contentsRect;
 
162
    QPointF referencePointAtTop = plane->translate( QPointF( 1, 0 ) );
 
163
    QPointF temp = plane->translate( QPointF( 0, 0 ) ) - referencePointAtTop;
 
164
    const double offset = temp.y();
 
165
    referencePointAtTop.setX( referencePointAtTop.x() - offset );
 
166
    contentsRect.setTopLeft( referencePointAtTop );
 
167
    contentsRect.setBottomRight( referencePointAtTop + QPointF( 2*offset, 2*offset) );
 
168
    return contentsRect;
 
169
}
 
170
/*
 
171
 
 
172
*/
 
173
 
 
174
 
 
175
void RingDiagram::paint( PaintContext* ctx )
 
176
{
 
177
    // note: Not having any data model assigned is no bug
 
178
    //       but we can not draw a diagram then either.
 
179
    if ( !checkInvariants(true) )
 
180
        return;
 
181
 
 
182
    const PieAttributes attrs( pieAttributes() );
 
183
 
 
184
        const int rCount = rowCount();
 
185
    const int colCount = columnCount();
 
186
 
 
187
    QRectF contentsRect( buildReferenceRect( polarCoordinatePlane() ) );
 
188
    contentsRect = ctx->rectangle();
 
189
    if( contentsRect.isEmpty() )
 
190
        return;
 
191
 
 
192
    DataValueTextInfoList list;
 
193
 
 
194
    d->startAngles = QVector< QVector<qreal> >( rCount, QVector<qreal>( colCount ) );
 
195
    d->angleLens = QVector< QVector<qreal> >( rCount, QVector<qreal>( colCount ) );
 
196
 
 
197
    // compute position
 
198
    d->size = qMin( contentsRect.width(), contentsRect.height() ); // initial size
 
199
 
 
200
    // if the pies explode, we need to give them additional space =>
 
201
    // make the basic size smaller
 
202
    qreal totalOffset = 0.0;
 
203
    for( int i = 0; i < rCount; ++i ){
 
204
        qreal maxOffsetInThisRow = 0.0;
 
205
        for( int j = 0; j < colCount; ++j ){
 
206
                const PieAttributes cellAttrs( pieAttributes( model()->index( i, j, rootIndex() ) ) );
 
207
                //qDebug() << cellAttrs.explodeFactor();
 
208
                const qreal explode = cellAttrs.explode() ? cellAttrs.explodeFactor() : 0.0;
 
209
                maxOffsetInThisRow = qMax( maxOffsetInThisRow, cellAttrs.gapFactor( false ) + explode );
 
210
        }
 
211
                if ( !d->expandWhenExploded )
 
212
                        maxOffsetInThisRow -= (qreal)i;
 
213
                if ( maxOffsetInThisRow > 0.0 )
 
214
                        totalOffset += maxOffsetInThisRow;
 
215
 
 
216
        // FIXME: What if explode factor of inner ring is > 1.0 ?
 
217
        //if ( !d->expandWhenExploded )
 
218
        //      break;
 
219
    }
 
220
 
 
221
    // explode factor is relative to width (outer r - inner r) of one ring
 
222
    if ( rCount > 0 )
 
223
        totalOffset /= ( rCount + 1 );
 
224
    d->size /= ( 1.0 + totalOffset );
 
225
 
 
226
 
 
227
    qreal x = ( contentsRect.width() == d->size ) ? 0.0 : ( ( contentsRect.width() - d->size ) / 2.0 );
 
228
    qreal y = ( contentsRect.height() == d->size ) ? 0.0 : ( ( contentsRect.height() - d->size ) / 2.0 );
 
229
    d->position = QRectF( x, y, d->size, d->size );
 
230
    d->position.translate( contentsRect.left(), contentsRect.top() );
 
231
 
 
232
    const PolarCoordinatePlane * plane = polarCoordinatePlane();
 
233
 
 
234
    bool atLeastOneValue = false; // guard against completely empty tables
 
235
    QVariant vValY;
 
236
 
 
237
    d->clearListOfAlreadyDrawnDataValueTexts();
 
238
    for ( int iRow = 0; iRow < rCount; ++iRow ) {
 
239
            const qreal sum = valueTotals( iRow );
 
240
            if( sum == 0.0 ) //nothing to draw
 
241
                continue;
 
242
            qreal currentValue = plane ? plane->startPosition() : 0.0;
 
243
            const qreal sectorsPerValue = 360.0 / sum;
 
244
 
 
245
            for ( int iColumn = 0; iColumn < colCount; ++iColumn ) {
 
246
                // is there anything at all at this column?
 
247
                bool bOK;
 
248
                const double cellValue = qAbs( model()->data( model()->index( iRow, iColumn, rootIndex() ) )
 
249
                    .toDouble( &bOK ) );
 
250
 
 
251
                if( bOK ){
 
252
                    d->startAngles[ iRow ][ iColumn ] = currentValue;
 
253
                    d->angleLens[ iRow ][ iColumn ] = cellValue * sectorsPerValue;
 
254
                    atLeastOneValue = true;
 
255
                } else { // mark as non-existent
 
256
                    d->angleLens[ iRow ][ iColumn ] = 0.0;
 
257
                    if ( iColumn > 0.0 )
 
258
                        d->startAngles[ iRow ][ iColumn ] = d->startAngles[ iRow ][ iColumn - 1 ];
 
259
                    else
 
260
                        d->startAngles[ iRow ][ iColumn ] = currentValue;
 
261
                }
 
262
                //qDebug() << "d->startAngles["<<iColumn<<"] == " << d->startAngles[ iColumn ]
 
263
                //         << " +  d->angleLens["<<iColumn<<"]" << d->angleLens[ iColumn ]
 
264
                //         << " = " << d->startAngles[ iColumn ]+d->angleLens[ iColumn ];
 
265
 
 
266
                currentValue = d->startAngles[ iRow ][ iColumn ] + d->angleLens[ iRow ][ iColumn ];
 
267
 
 
268
                drawOnePie( ctx->painter(), iRow, iColumn, granularity() );
 
269
            }
 
270
        }
 
271
}
 
272
 
 
273
#if defined ( Q_WS_WIN)
 
274
#define trunc(x) ((int)(x))
 
275
#endif
 
276
 
 
277
/**
 
278
  Internal method that draws one of the pies in a pie chart.
 
279
 
 
280
  \param painter the QPainter to draw in
 
281
  \param dataset the dataset to draw the pie for
 
282
  \param pie the pie to draw
 
283
  */
 
284
void RingDiagram::drawOnePie( QPainter* painter,
 
285
        uint dataset, uint pie,
 
286
        qreal granularity )
 
287
{
 
288
    // Is there anything to draw at all?
 
289
    const qreal angleLen = d->angleLens[ dataset ][ pie ];
 
290
    if ( angleLen ) {
 
291
        const QModelIndex index( model()->index( dataset, pie, rootIndex() ) );
 
292
        const PieAttributes attrs( pieAttributes( index ) );
 
293
 
 
294
        drawPieSurface( painter, dataset, pie, granularity );
 
295
    }
 
296
}
 
297
 
 
298
void RingDiagram::resize( const QSizeF& size )
 
299
{
 
300
    d->diagramSize = size;
 
301
}
 
302
 
 
303
/**
 
304
  Internal method that draws the surface of one of the pies in a pie chart.
 
305
 
 
306
  \param painter the QPainter to draw in
 
307
  \param dataset the dataset to draw the pie for
 
308
  \param pie the pie to draw
 
309
  */
 
310
void RingDiagram::drawPieSurface( QPainter* painter,
 
311
        uint dataset, uint pie,
 
312
        qreal granularity )
 
313
{
 
314
    // Is there anything to draw at all?
 
315
    qreal angleLen = d->angleLens[ dataset ][ pie ];
 
316
    if ( angleLen ) {
 
317
        qreal startAngle = d->startAngles[ dataset ][ pie ];
 
318
 
 
319
        QModelIndex index( model()->index( dataset, pie, rootIndex() ) );
 
320
        const PieAttributes attrs( pieAttributes( index ) );
 
321
 
 
322
        const int rCount = rowCount();
 
323
        const int colCount = columnCount();
 
324
 
 
325
        int iPoint = 0;
 
326
 
 
327
        QRectF drawPosition = d->position;//piePosition( dataset, pie );
 
328
 
 
329
        painter->setRenderHint ( QPainter::Antialiasing );
 
330
        painter->setBrush( brush( index ) );
 
331
        painter->setPen( pen( index ) );
 
332
//        painter->setPen( pen );
 
333
        //painter->setPen( Qt::red );
 
334
        if ( angleLen == 360 ) {
 
335
            // full circle, avoid nasty line in the middle
 
336
            // FIXME: Draw a complete ring here
 
337
            //painter->drawEllipse( drawPosition );
 
338
        } else {
 
339
            bool perfectMatch = false;
 
340
 
 
341
            qreal circularGap = 0.0;
 
342
 
 
343
            if ( attrs.gapFactor( true ) > 0.0 )
 
344
            {
 
345
                    // FIXME: Measure in degrees!
 
346
                    circularGap = attrs.gapFactor( true );
 
347
                    //qDebug() << "gapFactor=" << attrs.gapFactor( false );
 
348
            }
 
349
 
 
350
            QPolygonF poly;
 
351
 
 
352
            qreal degree = 0;
 
353
 
 
354
            qreal actualStartAngle = startAngle + circularGap;
 
355
            qreal actualAngleLen = angleLen - 2 * circularGap;
 
356
 
 
357
            qreal totalRadialExplode = 0.0;
 
358
            qreal maxRadialExplode = 0.0;
 
359
 
 
360
            qreal totalRadialGap = 0.0;
 
361
            qreal maxRadialGap = 0.0;
 
362
            for( uint i = rCount - 1; i > dataset; --i ){
 
363
                qreal maxRadialExplodeInThisRow = 0.0;
 
364
                qreal maxRadialGapInThisRow = 0.0;
 
365
                for( int j = 0; j < colCount; ++j ){
 
366
                        const PieAttributes cellAttrs( pieAttributes( model()->index( i, j, rootIndex() ) ) );
 
367
                        //qDebug() << cellAttrs.explodeFactor();
 
368
                        if ( d->expandWhenExploded )
 
369
                                maxRadialGapInThisRow = qMax( maxRadialGapInThisRow, cellAttrs.gapFactor( false ) );
 
370
                        if ( !cellAttrs.explode() )
 
371
                                continue;
 
372
                        // Don't use a gap for the very inner circle
 
373
                        if ( d->expandWhenExploded )
 
374
                                maxRadialExplodeInThisRow = qMax( maxRadialExplodeInThisRow, cellAttrs.explodeFactor() );
 
375
                }
 
376
                maxRadialExplode += maxRadialExplodeInThisRow;
 
377
                maxRadialGap += maxRadialGapInThisRow;
 
378
 
 
379
                // FIXME: What if explode factor of inner ring is > 1.0 ?
 
380
                //if ( !d->expandWhenExploded )
 
381
                //      break;
 
382
            }
 
383
 
 
384
            totalRadialGap = maxRadialGap + attrs.gapFactor( false );
 
385
            totalRadialExplode = attrs.explode() ? maxRadialExplode + attrs.explodeFactor() : maxRadialExplode;
 
386
 
 
387
            while ( degree <= actualAngleLen ) {
 
388
                const QPointF p = pointOnCircle( drawPosition, dataset, pie, false, actualStartAngle + degree, totalRadialGap, totalRadialExplode );
 
389
                poly.append( p );
 
390
                degree += granularity;
 
391
                iPoint++;
 
392
            }
 
393
            if( ! perfectMatch ){
 
394
                poly.append( pointOnCircle( drawPosition, dataset, pie, false, actualStartAngle + actualAngleLen, totalRadialGap, totalRadialExplode ) );
 
395
                iPoint++;
 
396
            }
 
397
 
 
398
            // The center point of the inner brink
 
399
            const QPointF innerCenterPoint( poly[ int(iPoint / 2) ] );
 
400
            
 
401
            actualStartAngle = startAngle + circularGap;
 
402
            actualAngleLen = angleLen - 2 * circularGap;
 
403
 
 
404
            degree = actualAngleLen;
 
405
 
 
406
            const int lastInnerBrinkPoint = iPoint;
 
407
            while ( degree >= 0 ){
 
408
                poly.append( pointOnCircle( drawPosition, dataset, pie, true, actualStartAngle + degree, totalRadialGap, totalRadialExplode ) );
 
409
                perfectMatch = (degree == 0);
 
410
                degree -= granularity;
 
411
                iPoint++;
 
412
            }
 
413
            // if necessary add one more point to fill the last small gap
 
414
            if( ! perfectMatch ){
 
415
                poly.append( pointOnCircle( drawPosition, dataset, pie, true, actualStartAngle, totalRadialGap, totalRadialExplode ) );
 
416
                iPoint++;
 
417
            }
 
418
 
 
419
            // The center point of the outer brink
 
420
            const QPointF outerCenterPoint( poly[ lastInnerBrinkPoint + int((iPoint - lastInnerBrinkPoint) / 2) ] );
 
421
            //qDebug() << poly;
 
422
            //find the value and paint it
 
423
            //fix value position
 
424
            const qreal sum = valueTotals( dataset );
 
425
            painter->drawPolygon( poly );
 
426
 
 
427
            const QPointF centerPoint = (innerCenterPoint + outerCenterPoint) / 2.0;
 
428
 
 
429
            paintDataValueText( painter, index, centerPoint, angleLen*sum / 360  );
 
430
 
 
431
        }
 
432
    }
 
433
}
 
434
 
 
435
 
 
436
/**
 
437
  * Auxiliary method returning a point to a given boundary
 
438
  * rectangle of the enclosed ellipse and an angle.
 
439
  */
 
440
QPointF RingDiagram::pointOnCircle( const QRectF& rect, int dataset, int pie, bool outer, qreal angle, qreal totalGapFactor, qreal totalExplodeFactor )
 
441
{
 
442
    qreal angleLen = d->angleLens[ dataset ][ pie ];
 
443
    qreal startAngle = d->startAngles[ dataset ][ pie ];
 
444
    QModelIndex index( model()->index( dataset, pie, rootIndex() ) );
 
445
    const PieAttributes attrs( pieAttributes( index ) );
 
446
 
 
447
        const int rCount = rowCount();
 
448
 
 
449
    //const qreal gapFactor = attrs.gapFactor( false );
 
450
 
 
451
    //qDebug() << "##" << attrs.explode();
 
452
    //if ( attrs.explodeFactor() != 0.0 )
 
453
    //  qDebug() << attrs.explodeFactor();
 
454
 
 
455
 
 
456
    qreal level = outer ? (rCount - dataset - 1) + 2 : (rCount - dataset - 1) + 1;
 
457
 
 
458
 
 
459
    //maxExplode /= rCount;
 
460
 
 
461
    //qDebug() << "dataset=" << dataset << "maxExplode=" << maxExplode;
 
462
 
 
463
    //level += maxExplode;
 
464
 
 
465
        const qreal offsetX = rCount > 0 ? level * rect.width() / ( ( rCount + 1 ) * 2 ) : 0.0;
 
466
        const qreal offsetY = rCount > 0 ? level * rect.height() / ( ( rCount + 1 ) * 2 ): 0.0;
 
467
        const qreal centerOffsetX = rCount > 0 ? totalExplodeFactor * rect.width() / ( ( rCount + 1 ) * 2 ) : 0.0;
 
468
        const qreal centerOffsetY = rCount > 0 ? totalExplodeFactor * rect.height() / ( ( rCount + 1 ) * 2 ): 0.0;
 
469
        const qreal gapOffsetX = rCount > 0 ? totalGapFactor * rect.width() / ( ( rCount + 1 ) * 2 ) : 0.0;
 
470
        const qreal gapOffsetY = rCount > 0 ? totalGapFactor * rect.height() / ( ( rCount + 1 ) * 2 ): 0.0;
 
471
 
 
472
    qreal explodeAngleRad = DEGTORAD( angle );
 
473
    qreal cosAngle = cos( explodeAngleRad );
 
474
    qreal sinAngle = -sin( explodeAngleRad );
 
475
    qreal explodeAngleCenterRad = DEGTORAD( startAngle + angleLen / 2.0 );
 
476
    qreal cosAngleCenter = cos( explodeAngleCenterRad );
 
477
    qreal sinAngleCenter = -sin( explodeAngleCenterRad );
 
478
    return QPointF( ( offsetX + gapOffsetX ) * cosAngle + centerOffsetX * cosAngleCenter + rect.center().x(),
 
479
                                ( offsetY + gapOffsetY ) * sinAngle + centerOffsetY * sinAngleCenter + rect.center().y() );
 
480
}
 
481
 
 
482
/*virtual*/
 
483
double RingDiagram::valueTotals() const
 
484
{
 
485
        const int rCount = rowCount();
 
486
    const int colCount = columnCount();
 
487
    double total = 0.0;
 
488
    for ( int i = 0; i < rCount; ++i ) {
 
489
        for ( int j = 0; j < colCount; ++j ) {
 
490
                total += qAbs(model()->data( model()->index( 0, j, rootIndex() ) ).toDouble());
 
491
                //qDebug() << model()->data( model()->index( 0, j, rootIndex() ) ).toDouble();
 
492
        }
 
493
    }
 
494
    return total;
 
495
}
 
496
 
 
497
double RingDiagram::valueTotals( int dataset ) const
 
498
{
 
499
    const int colCount = columnCount();
 
500
    double total = 0.0;
 
501
    for ( int j = 0; j < colCount; ++j ) {
 
502
      total += qAbs(model()->data( model()->index( dataset, j, rootIndex() ) ).toDouble());
 
503
      //qDebug() << model()->data( model()->index( 0, j, rootIndex() ) ).toDouble();
 
504
    }
 
505
    return total;
 
506
}
 
507
 
 
508
/*virtual*/
 
509
double RingDiagram::numberOfValuesPerDataset() const
 
510
{
 
511
    return model() ? model()->columnCount( rootIndex() ) : 0.0;
 
512
}
 
513
 
 
514
double RingDiagram::numberOfDatasets() const
 
515
{
 
516
    return model() ? model()->rowCount( rootIndex() ) : 0.0;
 
517
}
 
518
 
 
519
/*virtual*/
 
520
double RingDiagram::numberOfGridRings() const
 
521
{
 
522
    return 1;
 
523
}