# KDChartLegend.cpp

Go to the documentation of this file.

    00001 /****************************************************************************
    00002  ** Copyright (C) 2006 Klar�vdalens Datakonsult AB.  All rights reserved.
    00003  **
    00004  ** This file is part of the KD Chart library.
    00005  **
    00006  ** This file may be distributed and/or modified under the terms of the
    00007  ** GNU General Public License version 2 as published by the Free Software
    00008  ** Foundation and appearing in the file LICENSE.GPL included in the
    00009  ** packaging of this file.
    00010  **
    00011  ** Licensees holding valid commercial KD Chart licenses may use this file in
    00012  ** accordance with the KD Chart Commercial License Agreement provided with
    00013  ** the Software.
    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  ** See http://www.kdab.net/kdchart for
    00019  **   information about KDChart Commercial License Agreements.
    00020  **
    00021  ** Contact info@kdab.net if any conditions of this
    00022  ** licensing are not clear to you.
    00023  **
    00024  **********************************************************************/
    00025
    00026 #include "KDChartLegend.h"
    00027 #include "KDChartLegend_p.h"
    00028 #include <KDChartTextAttributes.h>
    00029 #include <KDChartMarkerAttributes.h>
    00030 #include <QFont>
    00031 #include <QPainter>
    00032 #include <QTextTableCell>
    00033 #include <QTextCursor>
    00034 #include <QTextCharFormat>
    00035 #include <QTextDocumentFragment>
    00036 #include <QTimer>
    00037 #include <QAbstractTextDocumentLayout>
    00038 #include <QtDebug>
    00039 #include <QLabel>
    00040 #include <KDChartAbstractDiagram.h>
    00041 #include "KDTextDocument.h"
    00042 #include <KDChartDiagramObserver.h>
    00043 #include <QGridLayout>
    00044 #include "KDChartLayoutItems.h"
    00045
    00046 #include <KDABLibFakes>
    00047
    00048 using namespace KDChart;
    00049
    00050 Legend::Private::Private() :
    00051     referenceArea(0),
    00052     position( Position::East ),
    00053     alignment( Qt::AlignCenter ),
    00054     relativePosition( RelativePosition() ),
    00055     orientation( Qt::Vertical ),
    00056     showLines( false ),
    00057     texts(),
    00058     textAttributes(),
    00059     titleText( QObject::tr( "Legend" ) ),
    00060     titleTextAttributes(),
    00061     spacing( 1 ),
    00062     useAutomaticMarkerSize( true ),
    00063     legendStyle( MarkersOnly )
    00064     //needRebuild( true )
    00065 {
    00066     // By default we specify a simple, hard point as the 'relative' position's ref. point,
    00067     // since we can not be sure that there will be any parent specified for the legend.
    00068     relativePosition.setReferencePoints(   PositionPoints( QPointF( 0.0, 0.0 ) ) );
    00069     relativePosition.setReferencePosition( Position::NorthWest );
    00070     relativePosition.setAlignment( Qt::AlignTop | Qt::AlignLeft );
    00071     relativePosition.setHorizontalPadding( KDChart::Measure( 4.0, KDChartEnums::MeasureCalculationModeAbsolute ) );
    00072     relativePosition.setVerticalPadding(   KDChart::Measure( 4.0, KDChartEnums::MeasureCalculationModeAbsolute ) );
    00073 }
    00074
    00075 Legend::Private::~Private()
    00076 {
    00077     // this bloc left empty intentionally
    00078 }
    00079
    00080
    00081
    00082 #define d d_func()
    00083
    00084
    00085 Legend::Legend( QWidget* parent ) :
    00086     AbstractAreaWidget( new Private(), parent )
    00087 {
    00088     d->referenceArea = parent;
    00089     init();
    00090 }
    00091
    00092 Legend::Legend( KDChart::AbstractDiagram* diagram, QWidget* parent ) :
    00093     AbstractAreaWidget( new Private(), parent )
    00094 {
    00095     d->referenceArea = parent;
    00096     init();
    00097     setDiagram( diagram );
    00098 }
    00099
    00100 Legend::~Legend()
    00101 {
    00102     emit destroyedLegend( this );
    00103 }
    00104
    00105 void Legend::init()
    00106 {
    00107     setSizePolicy( QSizePolicy::Fixed, QSizePolicy::Fixed );
    00108
    00109     d->layout = new QGridLayout( this );
    00110     d->layout->setMargin( 2 );
    00111     d->layout->setSpacing( d->spacing );
    00112     //setLayout( d->layout );
    00113
    00114     const Measure normalFontSizeTitle(  12, KDChartEnums::MeasureCalculationModeAbsolute );
    00115     const Measure normalFontSizeLabels( 10, KDChartEnums::MeasureCalculationModeAbsolute );
    00116     const Measure minimalFontSize(       4, KDChartEnums::MeasureCalculationModeAbsolute );
    00117
    00118     TextAttributes textAttrs;
    00119     textAttrs.setPen( QPen( Qt::black ) );
    00120     textAttrs.setFont( QFont( QLatin1String( "helvetica" ), 10, QFont::Normal, false ) );
    00121     textAttrs.setFontSize(        normalFontSizeLabels );
    00122     textAttrs.setMinimalFontSize( minimalFontSize );
    00123     setTextAttributes( textAttrs );
    00124
    00125     TextAttributes titleTextAttrs;
    00126     titleTextAttrs.setPen( QPen( Qt::black ) );
    00127     titleTextAttrs.setFont( QFont( QLatin1String( "helvetica" ), 12, QFont::Bold, false ) );
    00128     titleTextAttrs.setFontSize(        normalFontSizeTitle );
    00129     titleTextAttrs.setMinimalFontSize( minimalFontSize );
    00130     setTitleTextAttributes( titleTextAttrs );
    00131
    00132     FrameAttributes frameAttrs;
    00133     frameAttrs.setVisible( true );
    00134     frameAttrs.setPen( QPen( Qt::black ) );
    00135     frameAttrs.setPadding( 1 );
    00136     setFrameAttributes( frameAttrs );
    00137
    00138     d->position = Position::NorthEast;
    00139     d->alignment = Qt::AlignCenter;
    00140 }
    00141
    00142
    00143 QSize Legend::minimumSizeHint() const
    00144 {
    00145     return sizeHint();
    00146 }
    00147
    00148 //#define DEBUG_LEGEND_PAINT
    00149
    00150 QSize Legend::sizeHint() const
    00151 {
    00152 #ifdef DEBUG_LEGEND_PAINT
    00153     qDebug()  << "Legend::sizeHint() started";
    00154 #endif
    00155     Q_FOREACH( KDChart::AbstractLayoutItem* layoutItem, d->layoutItems ) {
    00156         layoutItem->sizeHint();
    00157     }
    00158     return AbstractAreaWidget::sizeHint();
    00159 }
    00160
    00161 void Legend::needSizeHint()
    00162 {
    00163     // Re-build the Legend's content, if it has not been build yet,
    00164     // or if the Legend's geometry has changed, resp.
    00165     buildLegend();
    00166 }
    00167
    00168 void Legend::resizeLayout( const QSize& size )
    00169 {
    00170 #ifdef DEBUG_LEGEND_PAINT
    00171     qDebug() << "Legend::resizeLayout started";
    00172 #endif
    00173     if( d->layout ){
    00174         d->layout->setGeometry( QRect(QPoint(0,0), size) );
    00175         activateTheLayout();
    00176     }
    00177 #ifdef DEBUG_LEGEND_PAINT
    00178     qDebug() << "Legend::resizeLayout done";
    00179 #endif
    00180 }
    00181
    00182 void Legend::activateTheLayout()
    00183 {
    00184     if( d->layout && d->layout->parent() )
    00185         d->layout->activate();
    00186 }
    00187
    00188
    00189 void Legend::setLegendStyle( LegendStyle style )
    00190 {
    00191     if( d->legendStyle == style ) return;
    00192     d->legendStyle = style;
    00193     setNeedRebuild();
    00194 }
    00195
    00196 Legend::LegendStyle Legend::legendStyle() const
    00197 {
    00198     return d->legendStyle;
    00199 }
    00200
    00201 Legend* Legend::clone() const
    00202 {
    00203     Legend* legend = new Legend( new Private( *d ), 0 );
    00204     legend->setTextAttributes( textAttributes() );
    00205     legend->setTitleTextAttributes( titleTextAttributes() );
    00206     legend->setFrameAttributes( frameAttributes() );
    00207     legend->setUseAutomaticMarkerSize( useAutomaticMarkerSize() );
    00208     legend->setPosition( position() );
    00209     legend->setAlignment( alignment() );
    00210     legend->setLegendStyle( legendStyle() );
    00211     return legend;
    00212 }
    00213
    00214
    00215 bool Legend::compare( const Legend* other )const
    00216 {
    00217     if( other == this ) return true;
    00218     if( ! other ){
    00219         //qDebug() << "Legend::compare() cannot compare to Null pointer";
    00220         return false;
    00221     }
    00222     /*
    00223     qDebug() << ( static_cast<const AbstractAreaBase*>(this)->compare( other ) );
    00224     qDebug() << (isVisible()              == other->isVisible());
    00225     qDebug() << (position()               == other->position());
    00226     qDebug() << (alignment()              == other->alignment());
    00227     qDebug() << (floatingPosition()       == other->floatingPosition());
    00228     qDebug() << (orientation()            == other->orientation());
    00229     qDebug() << (showLines()              == other->showLines());
    00230     qDebug() << (texts()                  == other->texts());
    00231     qDebug() << (brushes()                == other->brushes());
    00232     qDebug() << (pens()                   == other->pens());
    00233     qDebug() << (markerAttributes()       == other->markerAttributes());
    00234     qDebug() << (useAutomaticMarkerSize() == other->useAutomaticMarkerSize());
    00235     qDebug() << (textAttributes()         == other->textAttributes());
    00236     qDebug() << (titleText()              == other->titleText());
    00237     qDebug() << (titleTextAttributes()    == other->titleTextAttributes());
    00238     qDebug() << (spacing()                == other->spacing());
    00239     qDebug() << (legendStyle()            == other->legendStyle());
    00240     */
    00241     return  ( static_cast<const AbstractAreaBase*>(this)->compare( other ) ) &&
    00242             (isVisible()              == other->isVisible()) &&
    00243             (position()               == other->position()) &&
    00244             (alignment()              == other->alignment())&&
    00245             (floatingPosition()       == other->floatingPosition()) &&
    00246             (orientation()            == other->orientation())&&
    00247             (showLines()              == other->showLines())&&
    00248             (texts()                  == other->texts())&&
    00249             (brushes()                == other->brushes())&&
    00250             (pens()                   == other->pens())&&
    00251             (markerAttributes()       == other->markerAttributes())&&
    00252             (useAutomaticMarkerSize() == other->useAutomaticMarkerSize()) &&
    00253             (textAttributes()         == other->textAttributes()) &&
    00254             (titleText()              == other->titleText())&&
    00255             (titleTextAttributes()    == other->titleTextAttributes()) &&
    00256             (spacing()                == other->spacing()) &&
    00257             (legendStyle()            == other->legendStyle());
    00258 }
    00259
    00260
    00261 void Legend::paint( QPainter* painter )
    00262 {
    00263 #ifdef DEBUG_LEGEND_PAINT
    00264     qDebug() << "entering Legend::paint( QPainter* painter )";
    00265 #endif
    00266     // rule: We do not show a legend, if there is no diagram.
    00267     if( ! diagram() ) return;
    00268
    00269     // re-calculate/adjust the Legend's internal layout and contents, if needed:
    00270     //buildLegend();
    00271
    00272     // PENDING(kalle) Support palette
    00273
    00274     Q_FOREACH( KDChart::AbstractLayoutItem* layoutItem, d->layoutItems ) {
    00275         layoutItem->paint( painter );
    00276     }
    00277 #ifdef DEBUG_LEGEND_PAINT
    00278     qDebug() << "leaving Legend::paint( QPainter* painter )";
    00279 #endif
    00280 }
    00281
    00282
    00283 uint Legend::datasetCount() const
    00284 {
    00285     int modelLabelsCount = 0;
    00286     int modelBrushesCount = 0;
    00287     for (int i = 0; i < d->observers.size(); ++i) {
    00288         DiagramObserver * obs = d->observers.at(i);
    00289         modelLabelsCount  += obs->diagram()->datasetLabels().count();
    00290         modelBrushesCount += obs->diagram()->datasetBrushes().count();
    00291     }
    00292     Q_ASSERT( modelLabelsCount == modelBrushesCount );
    00293     return modelLabelsCount;
    00294 }
    00295
    00296
    00297 void Legend::setReferenceArea( const QWidget* area )
    00298 {
    00299     if( area == d->referenceArea ) return;
    00300     d->referenceArea = area;
    00301     setNeedRebuild();
    00302 }
    00303
    00304 const QWidget* Legend::referenceArea() const
    00305 {
    00306     //qDebug() << d->referenceArea;
    00307     return (d->referenceArea ? d->referenceArea : static_cast<const QWidget*>(parent()));
    00308 }
    00309
    00310
    00311 AbstractDiagram* Legend::diagram() const
    00312 {
    00313     if( d->observers.isEmpty() )
    00314         return 0;
    00315     return d->observers.first()->diagram();
    00316 }
    00317
    00318 DiagramList Legend::diagrams() const
    00319 {
    00320     DiagramList list;
    00321     for (int i = 0; i < d->observers.size(); ++i)
    00322         list << d->observers.at(i)->diagram();
    00323     return list;
    00324 }
    00325
    00326 ConstDiagramList Legend::constDiagrams() const
    00327 {
    00328     ConstDiagramList list;
    00329     for (int i = 0; i < d->observers.size(); ++i)
    00330         list << d->observers.at(i)->diagram();
    00331     return list;
    00332 }
    00333
    00334 void Legend::addDiagram( AbstractDiagram* newDiagram )
    00335 {
    00336     if ( newDiagram )
    00337     {
    00338         DiagramObserver* observer = new DiagramObserver( newDiagram, this );
    00339
    00340         DiagramObserver* oldObs = d->findObserverForDiagram( newDiagram );
    00341         if( oldObs ){
    00342             delete oldObs;
    00343             d->observers[ d->observers.indexOf( oldObs ) ] = observer;
    00344         }else{
    00345             d->observers.append( observer );
    00346         }
    00347         connect( observer, SIGNAL( diagramDestroyed(AbstractDiagram*) ),
    00348                         SLOT( resetDiagram(AbstractDiagram*) ));
    00349         connect( observer, SIGNAL( diagramDataChanged(AbstractDiagram*) ),
    00350                  SLOT( setNeedRebuild() ));
    00351         connect( observer, SIGNAL( diagramDataHidden(AbstractDiagram*) ),
    00352                  SLOT( setNeedRebuild() ));
    00353         connect( observer, SIGNAL( diagramAttributesChanged(AbstractDiagram*) ),
    00354                         SLOT( setNeedRebuild() ));
    00355         setNeedRebuild();
    00356     }
    00357 }
    00358
    00359 void Legend::removeDiagram( AbstractDiagram* oldDiagram )
    00360 {
    00361     if( oldDiagram ){
    00362         DiagramObserver* oldObs = d->findObserverForDiagram( oldDiagram );
    00363         if( oldObs ){
    00364             //qDebug() << "before delete oldObs;";
    00365             delete oldObs;
    00366             //qDebug() << "after delete oldObs;";
    00367             d->observers.removeAt( d->observers.indexOf( oldObs ) );
    00368             //qDebug() << "after d->observers.removeAt()";
    00369         }
    00370         setNeedRebuild();
    00371     }
    00372 }
    00373
    00374 void Legend::removeDiagrams()
    00375 {
    00376     for (int i = 0; i < d->observers.size(); ++i)
    00377         removeDiagram( d->observers.at(i)->diagram() );
    00378 }
    00379
    00380 void Legend::replaceDiagram( AbstractDiagram* newDiagram,
    00381                              AbstractDiagram* oldDiagram )
    00382 {
    00383     KDChart::AbstractDiagram* old = oldDiagram;
    00384     if( ! d->observers.isEmpty() && ! old ){
    00385         old = d->observers.first()->diagram();
    00386         if( ! old )
    00387             d->observers.removeFirst(); // first entry had a 0 diagram
    00388     }
    00389     if( old )
    00390         removeDiagram( old );
    00391     if( newDiagram )
    00392         addDiagram( newDiagram );
    00393 }
    00394
    00395 void Legend::setDiagram( KDChart::AbstractDiagram* newDiagram )
    00396 {
    00397     replaceDiagram( newDiagram );
    00398 }
    00399
    00400 void Legend::resetDiagram( AbstractDiagram* oldDiagram )
    00401 {
    00402     //qDebug() << oldDiagram;
    00403     removeDiagram( oldDiagram );
    00404 }
    00405
    00406 void Legend::setVisible( bool visible )
    00407 {
    00408     QWidget::setVisible( visible );
    00409     emitPositionChanged();
    00410 }
    00411
    00412 void Legend::setNeedRebuild()
    00413 {
    00414     //qDebug() << "setNeedRebuild()";
    00415     buildLegend();
    00416     sizeHint();
    00417 }
    00418
    00419 void Legend::setPosition( Position position )
    00420 {
    00421     d->position = position;
    00422     emitPositionChanged();
    00423 }
    00424
    00425 void Legend::emitPositionChanged()
    00426 {
    00427     emit positionChanged( this );
    00428     emit propertiesChanged();
    00429 }
    00430
    00431
    00432 Position Legend::position() const
    00433 {
    00434     return d->position;
    00435 }
    00436
    00437 void Legend::setAlignment( Qt::Alignment alignment )
    00438 {
    00439     d->alignment = alignment;
    00440     emitPositionChanged();
    00441 }
    00442
    00443 Qt::Alignment Legend::alignment() const
    00444 {
    00445     return d->alignment;
    00446 }
    00447
    00448 void Legend::setFloatingPosition( const RelativePosition& relativePosition )
    00449 {
    00450     d->position = Position::Floating;
    00451     if( d->relativePosition != relativePosition ){
    00452         d->relativePosition  = relativePosition;
    00453         emitPositionChanged();
    00454     }
    00455 }
    00456
    00457 const RelativePosition Legend::floatingPosition() const
    00458 {
    00459     return d->relativePosition;
    00460 }
    00461
    00462 void Legend::setOrientation( Qt::Orientation orientation )
    00463 {
    00464     if( d->orientation == orientation ) return;
    00465     d->orientation = orientation;
    00466     setNeedRebuild();
    00467     emitPositionChanged();
    00468 }
    00469
    00470 Qt::Orientation Legend::orientation() const
    00471 {
    00472     return d->orientation;
    00473 }
    00474
    00475 void Legend::setShowLines( bool legendShowLines )
    00476 {
    00477     if( d->showLines == legendShowLines ) return;
    00478     d->showLines = legendShowLines;
    00479     setNeedRebuild();
    00480     emitPositionChanged();
    00481 }
    00482
    00483 bool Legend::showLines() const
    00484 {
    00485     return d->showLines;
    00486 }
    00487
    00488 void Legend::setUseAutomaticMarkerSize( bool useAutomaticMarkerSize )
    00489 {
    00490     d->useAutomaticMarkerSize = useAutomaticMarkerSize;
    00491     setNeedRebuild();
    00492     emitPositionChanged();
    00493 }
    00494
    00495 bool Legend::useAutomaticMarkerSize() const
    00496 {
    00497     return d->useAutomaticMarkerSize;
    00498 }
    00499
    00505 void Legend::resetTexts()
    00506 {
    00507     if( ! d->texts.count() ) return;
    00508     d->texts.clear();
    00509     setNeedRebuild();
    00510 }
    00511
    00512 void Legend::setText( uint dataset, const QString& text )
    00513 {
    00514     if( d->texts[ dataset ] == text ) return;
    00515     d->texts[ dataset ] = text;
    00516     setNeedRebuild();
    00517 }
    00518
    00519 QString Legend::text( uint dataset ) const
    00520 {
    00521     if( d->texts.find( dataset ) != d->texts.end() ){
    00522         //qDebug() << "Legend::text(" << dataset << ") returning d->texts[" << dataset << "] :" << d->texts[ dataset ];
    00523         return d->texts[ dataset ];
    00524     }else{
    00525         //qDebug() << "Legend::text(" << dataset << ") returning d->modelLabels[" << dataset << "] :" << d->modelLabels[ dataset ];
    00526         return d->modelLabels[ dataset ];
    00527     }
    00528 }
    00529
    00530 const QMap<uint,QString> Legend::texts() const
    00531 {
    00532     return d->texts;
    00533 }
    00534
    00535 void Legend::setColor( uint dataset, const QColor& color )
    00536 {
    00537     if( d->brushes[ dataset ] == color ) return;
    00538     d->brushes[ dataset ] = color;
    00539     setNeedRebuild();
    00540 }
    00541
    00542 void Legend::setBrush( uint dataset, const QBrush& brush )
    00543 {
    00544     if( d->brushes[ dataset ] == brush ) return;
    00545     d->brushes[ dataset ] = brush;
    00546     setNeedRebuild();
    00547 }
    00548
    00549 QBrush Legend::brush( uint dataset ) const
    00550 {
    00551     if( d->brushes.find( dataset ) != d->brushes.end() )
    00552         return d->brushes[ dataset ];
    00553     else
    00554         return d->modelBrushes[ dataset ];
    00555 }
    00556
    00557 const QMap<uint,QBrush> Legend::brushes() const
    00558 {
    00559     return d->brushes;
    00560 }
    00561
    00562
    00563 void Legend::setBrushesFromDiagram( KDChart::AbstractDiagram* diagram )
    00564 {
    00565     bool bChangesDone = false;
    00566     QList<QBrush> datasetBrushes = diagram->datasetBrushes();
    00567     for( int i = 0; i < datasetBrushes.count(); i++ ){
    00568         if( d->brushes[ i ] != datasetBrushes[ i ] ){
    00569             d->brushes[ i ]  = datasetBrushes[ i ];
    00570             bChangesDone = true;
    00571         }
    00572     }
    00573     if( bChangesDone )
    00574         setNeedRebuild();
    00575 }
    00576
    00577
    00578 void Legend::setPen( uint dataset, const QPen& pen )
    00579 {
    00580     if( d->pens[dataset] == pen ) return;
    00581     d->pens[dataset] = pen;
    00582     setNeedRebuild();
    00583 }
    00584
    00585 QPen Legend::pen( uint dataset ) const
    00586 {
    00587     if( d->pens.find( dataset ) != d->pens.end() )
    00588         return d->pens[dataset];
    00589     else
    00590         return d->modelPens[ dataset ];
    00591 }
    00592
    00593 const QMap<uint,QPen> Legend::pens() const
    00594 {
    00595     return d->pens;
    00596 }
    00597
    00598
    00599 void Legend::setMarkerAttributes( uint dataset, const MarkerAttributes& markerAttributes )
    00600 {
    00601     if( d->markerAttributes[dataset] == markerAttributes ) return;
    00602     d->markerAttributes[ dataset ] = markerAttributes;
    00603     setNeedRebuild();
    00604 }
    00605
    00606 MarkerAttributes Legend::markerAttributes( uint dataset ) const
    00607 {
    00608     if( d->markerAttributes.find( dataset ) != d->markerAttributes.end() )
    00609         return d->markerAttributes[ dataset ];
    00610     else if ( static_cast<uint>( d->modelMarkers.count() ) > dataset )
    00611         return d->modelMarkers[ dataset ];
    00612     return MarkerAttributes();
    00613 }
    00614
    00615 const QMap<uint, MarkerAttributes> Legend::markerAttributes() const
    00616 {
    00617     return d->markerAttributes;
    00618 }
    00619
    00620
    00621 void Legend::setTextAttributes( const TextAttributes &a )
    00622 {
    00623     if( d->textAttributes == a ) return;
    00624     d->textAttributes = a;
    00625     setNeedRebuild();
    00626 }
    00627
    00628 TextAttributes Legend::textAttributes() const
    00629 {
    00630     return d->textAttributes;
    00631 }
    00632
    00633 void Legend::setTitleText( const QString& text )
    00634 {
    00635     if( d->titleText == text ) return;
    00636     d->titleText = text;
    00637     setNeedRebuild();
    00638 }
    00639
    00640 QString Legend::titleText() const
    00641 {
    00642     return d->titleText;
    00643 }
    00644
    00645 void Legend::setTitleTextAttributes( const TextAttributes &a )
    00646 {
    00647     if( d->titleTextAttributes == a ) return;
    00648     d->titleTextAttributes = a;
    00649     setNeedRebuild();
    00650 }
    00651
    00652 TextAttributes Legend::titleTextAttributes() const
    00653 {
    00654     return d->titleTextAttributes;
    00655 }
    00656
    00657 void Legend::forceRebuild()
    00658 {
    00659 #ifdef DEBUG_LEGEND_PAINT
    00660     qDebug() << "entering Legend::forceRebuild()";
    00661 #endif
    00662     //setSpacing(d->layout->spacing());
    00663     buildLegend();
    00664 #ifdef DEBUG_LEGEND_PAINT
    00665     qDebug() << "leaving Legend::forceRebuild()";
    00666 #endif
    00667 }
    00668
    00669 void Legend::setSpacing( uint space )
    00670 {
    00671     if( d->spacing == space && d->layout->spacing() == static_cast<int>(space) ) return;
    00672     d->spacing = space;
    00673     d->layout->setSpacing( space );
    00674     setNeedRebuild();
    00675 }
    00676
    00677 uint Legend::spacing() const
    00678 {
    00679     return d->spacing;
    00680 }
    00681
    00682 void Legend::setDefaultColors()
    00683 {
    00684     setColor(  0, Qt::red );
    00685     setColor(  1, Qt::green );
    00686     setColor(  2, Qt::blue );
    00687     setColor(  3, Qt::cyan );
    00688     setColor(  4, Qt::magenta );
    00689     setColor(  5, Qt::yellow );
    00690     setColor(  6, Qt::darkRed );
    00691     setColor(  7, Qt::darkGreen );
    00692     setColor(  8, Qt::darkBlue );
    00693     setColor(  9, Qt::darkCyan );
    00694     setColor( 10, Qt::darkMagenta );
    00695     setColor( 11, Qt::darkYellow );
    00696 }
    00697
    00698 void Legend::setRainbowColors()
    00699 {
    00700     setColor(  0, QColor(255,  0,196) );
    00701     setColor(  1, QColor(255,  0, 96) );
    00702     setColor(  2, QColor(255, 128,64) );
    00703     setColor(  3, Qt::yellow );
    00704     setColor(  4, Qt::green );
    00705     setColor(  5, Qt::cyan );
    00706     setColor(  6, QColor( 96, 96,255) );
    00707     setColor(  7, QColor(160,  0,255) );
    00708     for( int i = 8; i < 16; ++i )
    00709         setColor( i, brush( i - 8 ).color().light() );
    00710 }
    00711
    00712 void Legend::setSubduedColors( bool ordered )
    00713 {
    00714 static const int NUM_SUBDUEDCOLORS = 18;
    00715 static const QColor SUBDUEDCOLORS[ NUM_SUBDUEDCOLORS ] = {
    00716     QColor( 0xe0,0x7f,0x70 ),
    00717     QColor( 0xe2,0xa5,0x6f ),
    00718     QColor( 0xe0,0xc9,0x70 ),
    00719     QColor( 0xd1,0xe0,0x70 ),
    00720     QColor( 0xac,0xe0,0x70 ),
    00721     QColor( 0x86,0xe0,0x70 ),
    00722     QColor( 0x70,0xe0,0x7f ),
    00723     QColor( 0x70,0xe0,0xa4 ),
    00724     QColor( 0x70,0xe0,0xc9 ),
    00725     QColor( 0x70,0xd1,0xe0 ),
    00726     QColor( 0x70,0xac,0xe0 ),
    00727     QColor( 0x70,0x86,0xe0 ),
    00728     QColor( 0x7f,0x70,0xe0 ),
    00729     QColor( 0xa4,0x70,0xe0 ),
    00730     QColor( 0xc9,0x70,0xe0 ),
    00731     QColor( 0xe0,0x70,0xd1 ),
    00732     QColor( 0xe0,0x70,0xac ),
    00733     QColor( 0xe0,0x70,0x86 ),
    00734 };
    00735     if( ordered )
    00736         for(int i=0; i<NUM_SUBDUEDCOLORS; ++i)
    00737             setColor( i, SUBDUEDCOLORS[i] );
    00738     else{
    00739         setColor( 0, SUBDUEDCOLORS[ 0] );
    00740         setColor( 1, SUBDUEDCOLORS[ 5] );
    00741         setColor( 2, SUBDUEDCOLORS[10] );
    00742         setColor( 3, SUBDUEDCOLORS[15] );
    00743         setColor( 4, SUBDUEDCOLORS[ 2] );
    00744         setColor( 5, SUBDUEDCOLORS[ 7] );
    00745         setColor( 6, SUBDUEDCOLORS[12] );
    00746         setColor( 7, SUBDUEDCOLORS[17] );
    00747         setColor( 8, SUBDUEDCOLORS[ 4] );
    00748         setColor( 9, SUBDUEDCOLORS[ 9] );
    00749         setColor(10, SUBDUEDCOLORS[14] );
    00750         setColor(11, SUBDUEDCOLORS[ 1] );
    00751         setColor(12, SUBDUEDCOLORS[ 6] );
    00752         setColor(13, SUBDUEDCOLORS[11] );
    00753         setColor(14, SUBDUEDCOLORS[16] );
    00754         setColor(15, SUBDUEDCOLORS[ 3] );
    00755         setColor(16, SUBDUEDCOLORS[ 8] );
    00756         setColor(17, SUBDUEDCOLORS[13] );
    00757     }
    00758 }
    00759
    00760 void Legend::resizeEvent ( QResizeEvent * event )
    00761 {
    00762 #ifdef DEBUG_LEGEND_PAINT
    00763     qDebug() << "Legend::resizeEvent() called";
    00764 #endif
    00765     forceRebuild();
    00766     sizeHint();
    00767     QTimer::singleShot(0, this, SLOT(emitPositionChanged()));
    00768 }
    00769
    00770 void Legend::buildLegend()
    00771 {
    00772     /*
    00773     if( !d->needRebuild ) {
    00774 #ifdef DEBUG_LEGEND_PAINT
    00775         qDebug() << "leaving Legend::buildLegend() with NO action (was already build)";
    00776 #endif
    00777         // Note: We do *not* need to send positionChanged here,
    00778         //       because we send it in the resizeEvent, so layouting
    00779         //       is done at the right time.
    00780         return;
    00781     }
    00782 #ifdef DEBUG_LEGEND_PAINT
    00783     qDebug() << "entering Legend::buildLegend() **********************************";
    00784 #endif
    00785     d->needRebuild = false;
    00786     */
    00787
    00788     Q_FOREACH( QLayoutItem* layoutItem, d->layoutItems ) {
    00789         d->layout->removeItem( layoutItem );
    00790     }
    00791     qDeleteAll( d->layoutItems );
    00792     d->layoutItems.clear();
    00793
    00794     if( orientation() == Qt::Vertical ) {
    00795         d->layout->setColumnStretch( 4, 1 );
    00796     } else {
    00797         d->layout->setColumnStretch( 4, 0 );
    00798     }
    00799
    00800     d->modelLabels.clear();
    00801     d->modelBrushes.clear();
    00802     d->modelPens.clear();
    00803     d->modelMarkers.clear();
    00804     // retrieve the diagrams' settings for all non-hidden datasets
    00805     for (int i = 0; i < d->observers.size(); ++i){
    00806         const AbstractDiagram* diagram = d->observers.at(i)->diagram();
    00807         if( diagram ){
    00808             //qDebug() << "accessing" << diagram;
    00809             const QStringList             diagramLabels(  diagram->datasetLabels()  );
    00810             const QList<QBrush>           diagramBrushes( diagram->datasetBrushes() );
    00811             const QList<QPen>             diagramPens(    diagram->datasetPens()    );
    00812             const QList<MarkerAttributes> diagramMarkers( diagram->datasetMarkers() );
    00813             for ( int dataset = 0; dataset < diagramLabels.count(); dataset++ ) {
    00814                 // only show the label if the diagrams is NOT having the dataset set to hidden
    00815                 if( ! diagram->isHidden( dataset ) ){
    00816                     d->modelLabels  += diagramLabels[   dataset ];
    00817                     d->modelBrushes += diagramBrushes[  dataset ];
    00818                     d->modelPens    += diagramPens[     dataset ];
    00819                     d->modelMarkers += diagramMarkers[  dataset ];
    00820                 }
    00821             }
    00822         }
    00823     }
    00824
    00825     Q_ASSERT( d->modelLabels.count() == d->modelBrushes.count() );
    00826
    00827     // legend caption
    00828     if( !titleText().isEmpty() && titleTextAttributes().isVisible() ) {
    00829         // PENDING(kalle) Other properties!
    00830         KDChart::TextLayoutItem* titleItem =
    00831             new KDChart::TextLayoutItem( titleText(),
    00832                 titleTextAttributes(),
    00833                 referenceArea(),
    00834                 (orientation() == Qt::Vertical)
    00835                 ? KDChartEnums::MeasureOrientationMinimum
    00836                 : KDChartEnums::MeasureOrientationHorizontal,
    00837                 Qt::AlignCenter );
    00838         titleItem->setParentWidget( this );
    00839
    00840         d->layoutItems << titleItem;
    00841         if( orientation() == Qt::Vertical )
    00842             d->layout->addItem( titleItem, 0, 0, 1, 5, Qt::AlignCenter );
    00843         else
    00844             d->layout->addItem( titleItem, 0, 0, 1, d->modelLabels.count() ? (d->modelLabels.count()*4) : 1, Qt::AlignCenter );
    00845
    00846         // The line between the title and the legend items, if any.
    00847         if( showLines() && d->modelLabels.count() ) {
    00848             KDChart::HorizontalLineLayoutItem* lineItem = new KDChart::HorizontalLineLayoutItem();
    00849             d->layoutItems << lineItem;
    00850             if( orientation() == Qt::Vertical )
    00851                 d->layout->addItem( lineItem, 1, 0, 1, 5, Qt::AlignCenter );
    00852             else
    00853                 d->layout->addItem( lineItem, 1, 0, 1, d->modelLabels.count()*4, Qt::AlignCenter );
    00854         }
    00855     }
    00856
    00857     const KDChartEnums::MeasureOrientation orient =
    00858             (orientation() == Qt::Vertical)
    00859             ? KDChartEnums::MeasureOrientationMinimum
    00860             : KDChartEnums::MeasureOrientationHorizontal;
    00861     const TextAttributes labelAttrs( textAttributes() );
    00862     const qreal fontHeight = labelAttrs.calculatedFontSize( referenceArea(), orient );
    00863     const LegendStyle style = legendStyle();
    00864     //qDebug() << "fontHeight:" << fontHeight;
    00865
    00866     const bool bShowMarkers = (style != LinesOnly);
    00867
    00868     QSizeF maxMarkersSize(1.0, 1.0);
    00869     QVector <MarkerAttributes> markerAttrs( d->modelLabels.count() );
    00870     if( bShowMarkers ){
    00871         for ( int dataset = 0; dataset < d->modelLabels.count(); ++dataset ) {
    00872             markerAttrs[dataset] = markerAttributes( dataset );
    00873             QSizeF siz;
    00874             if( useAutomaticMarkerSize() ||
    00875                 ! markerAttrs[dataset].markerSize().isValid() )
    00876             {
    00877                 siz = QSizeF(fontHeight, fontHeight);
    00878                 markerAttrs[dataset].setMarkerSize( siz );
    00879             }else{
    00880                 siz = markerAttrs[dataset].markerSize();
    00881             }
    00882             maxMarkersSize =
    00883                     QSizeF(qMax(maxMarkersSize.width(),  siz.width()),
    00884                            qMax(maxMarkersSize.height(), siz.height()));
    00885         }
    00886     }
    00887
    00888     // If we show a marker on a line, we paint it after 4 pixels
    00889     // of the line have been painted. This allows to see the line style
    00890     // at the right side of the marker without the line needing to
    00891     // be too long.
    00892     // (having the marker in the middle of the line would require longer lines)
    00893     const int markerOffsOnLine = 8;
    00894
    00895     int maxLineLength = 18;
    00896     {
    00897         bool hasComplexPenStyle = false;
    00898         for ( int dataset = 0; dataset < d->modelLabels.count(); ++dataset ){
    00899             const QPen pn = pen(dataset);
    00900             const Qt::PenStyle ps = pn.style();
    00901             if( ps != Qt::NoPen ){
    00902                 maxLineLength = qMax( pn.width() * 18, maxLineLength );
    00903                 if( ps != Qt::SolidLine )
    00904                     hasComplexPenStyle = true;
    00905             }
    00906         }
    00907         if( hasComplexPenStyle && bShowMarkers )
    00908             maxLineLength =
    00909                     maxLineLength + markerOffsOnLine +
    00910                     static_cast<int>(maxMarkersSize.width());
    00911     }
    00912
    00913     for ( int dataset = 0; dataset < d->modelLabels.count(); ++dataset ) {
    00914         KDChart::AbstractLayoutItem* markerLineItem = 0;
    00915         switch( style ){
    00916             case( MarkersOnly ):
    00917                 markerLineItem = new KDChart::MarkerLayoutItem(
    00918                         diagram(),
    00919                         markerAttrs[dataset],
    00920                         brush( dataset ),
    00921                         pen( dataset ),
    00922                         Qt::AlignLeft );
    00923                 break;
    00924             case( LinesOnly ):
    00925                 markerLineItem = new KDChart::LineLayoutItem(
    00926                         diagram(),
    00927                         maxLineLength,
    00928                         pen( dataset ),
    00929                         Qt::AlignCenter );
    00930                 break;
    00931             case( MarkersAndLines ):
    00932                 markerLineItem = new KDChart::LineWithMarkerLayoutItem(
    00933                         diagram(),
    00934                         maxLineLength,
    00935                         pen( dataset ),
    00936                         markerOffsOnLine,
    00937                         markerAttrs[dataset],
    00938                         brush( dataset ),
    00939                         pen( dataset ),
    00940                         Qt::AlignCenter );
    00941                 break;
    00942             default:
    00943                 Q_ASSERT( false ); // all styles need to be handled
    00944         }
    00945         if( markerLineItem ){
    00946             d->layoutItems << markerLineItem;
    00947             if( orientation() == Qt::Vertical )
    00948                 d->layout->addItem( markerLineItem,
    00949                                     dataset*2+2, // first row is title, second is line
    00950                                     1,
    00951                                     1, 1, Qt::AlignCenter );
    00952             else
    00953                 d->layout->addItem( markerLineItem,
    00954                                     2, // all in row two
    00955                                     dataset*4 );
    00956         }
    00957
    00958         // PENDING(kalle) Other properties!
    00959         KDChart::TextLayoutItem* labelItem =
    00960             new KDChart::TextLayoutItem( text( dataset ),
    00961                 labelAttrs,
    00962                 referenceArea(), orient,
    00963                 Qt::AlignLeft );
    00964         labelItem->setParentWidget( this );
    00965
    00966         d->layoutItems << labelItem;
    00967         if( orientation() == Qt::Vertical )
    00968             d->layout->addItem( labelItem,
    00969                                 dataset*2+2, // first row is title, second is line
    00970                                 3 );
    00971         else
    00972             d->layout->addItem( labelItem,
    00973                                 2, // all in row two
    00974                                 dataset*4+1 );
    00975
    00976         // horizontal lines (only in vertical mode, and not after the last item)
    00977         if( orientation() == Qt::Vertical && showLines() && dataset != d->modelLabels.count()-1 ) {
    00978             KDChart::HorizontalLineLayoutItem* lineItem = new KDChart::HorizontalLineLayoutItem();
    00979             d->layoutItems << lineItem;
    00980             d->layout->addItem( lineItem,
    00981                                 dataset*2+1+2,
    00982                                 0,
    00983                                 1, 5, Qt::AlignCenter );
    00984         }
    00985
    00986         // vertical lines (only in horizontal mode, and not after the last item)
    00987         if( orientation() == Qt::Horizontal && showLines() && dataset != d->modelLabels.count()-1 ) {
    00988             KDChart::VerticalLineLayoutItem* lineItem = new KDChart::VerticalLineLayoutItem();
    00989             d->layoutItems << lineItem;
    00990             d->layout->addItem( lineItem,
    00991                                 2, // all in row two
    00992                                 style == MarkersAndLines ? dataset*4+3 : dataset*4+2 ,
    00993                                 1, 1, Qt::AlignCenter );
    00994         }
    00995
    00996         if( orientation() != Qt::Vertical ) { // Horizontal needs a spacer
    00997             d->layout->addItem( new QSpacerItem( spacing(), 1 ),
    00998                                 2, // all in row two
    00999                                 dataset*4+3 );
    01000         }
    01001     }
    01002
    01003     // vertical line (only in vertical mode)
    01004     if( orientation() == Qt::Vertical && showLines() && d->modelLabels.count() ) {
    01005         KDChart::VerticalLineLayoutItem* lineItem = new KDChart::VerticalLineLayoutItem();
    01006         d->layoutItems << lineItem;
    01007         d->layout->addItem( lineItem, 2, 2, d->modelLabels.count()*2, 1 );
    01008     }
    01009
    01010     // This line is absolutely necessary, otherwise: #2516.
    01011     activateTheLayout();
    01012
    01013     emit propertiesChanged();
    01014     //emit positionChanged( this );
    01015     //emitPositionChanged();
    01016 #ifdef DEBUG_LEGEND_PAINT
    01017     qDebug() << "leaving Legend::buildLegend()";
    01018 #endif
    01019 }
    01020