KDChartLegend.cpp

Go to the documentation of this file.
00001 /****************************************************************************
00002  ** Copyright (C) 2007 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 
00204 Legend* Legend::clone() const
00205 {
00206     Legend* legend = new Legend( new Private( *d ), 0 );
00207     legend->setTextAttributes( textAttributes() );
00208     legend->setTitleTextAttributes( titleTextAttributes() );
00209     legend->setFrameAttributes( frameAttributes() );
00210     legend->setUseAutomaticMarkerSize( useAutomaticMarkerSize() );
00211     legend->setPosition( position() );
00212     legend->setAlignment( alignment() );
00213     legend->setLegendStyle( legendStyle() );
00214     return legend;
00215 }
00216 
00217 
00218 bool Legend::compare( const Legend* other )const
00219 {
00220     if( other == this ) return true;
00221     if( ! other ){
00222         //qDebug() << "Legend::compare() cannot compare to Null pointer";
00223         return false;
00224     }
00225     /*
00226     qDebug() << ( static_cast<const AbstractAreaBase*>(this)->compare( other ) );
00227     qDebug() << (isVisible()              == other->isVisible());
00228     qDebug() << (position()               == other->position());
00229     qDebug() << (alignment()              == other->alignment());
00230     qDebug() << (floatingPosition()       == other->floatingPosition());
00231     qDebug() << (orientation()            == other->orientation());
00232     qDebug() << (showLines()              == other->showLines());
00233     qDebug() << (texts()                  == other->texts());
00234     qDebug() << (brushes()                == other->brushes());
00235     qDebug() << (pens()                   == other->pens());
00236     qDebug() << (markerAttributes()       == other->markerAttributes());
00237     qDebug() << (useAutomaticMarkerSize() == other->useAutomaticMarkerSize());
00238     qDebug() << (textAttributes()         == other->textAttributes());
00239     qDebug() << (titleText()              == other->titleText());
00240     qDebug() << (titleTextAttributes()    == other->titleTextAttributes());
00241     qDebug() << (spacing()                == other->spacing());
00242     qDebug() << (legendStyle()            == other->legendStyle());
00243     */
00244     return  ( static_cast<const AbstractAreaBase*>(this)->compare( other ) ) &&
00245             (isVisible()              == other->isVisible()) &&
00246             (position()               == other->position()) &&
00247             (alignment()              == other->alignment())&&
00248             (floatingPosition()       == other->floatingPosition()) &&
00249             (orientation()            == other->orientation())&&
00250             (showLines()              == other->showLines())&&
00251             (texts()                  == other->texts())&&
00252             (brushes()                == other->brushes())&&
00253             (pens()                   == other->pens())&&
00254             (markerAttributes()       == other->markerAttributes())&&
00255             (useAutomaticMarkerSize() == other->useAutomaticMarkerSize()) &&
00256             (textAttributes()         == other->textAttributes()) &&
00257             (titleText()              == other->titleText())&&
00258             (titleTextAttributes()    == other->titleTextAttributes()) &&
00259             (spacing()                == other->spacing()) &&
00260             (legendStyle()            == other->legendStyle());
00261 }
00262 
00263 
00264 void Legend::paint( QPainter* painter )
00265 {
00266 #ifdef DEBUG_LEGEND_PAINT
00267     qDebug() << "entering Legend::paint( QPainter* painter )";
00268 #endif
00269     // rule: We do not show a legend, if there is no diagram.
00270     if( ! diagram() ) return;
00271 
00272     // re-calculate/adjust the Legend's internal layout and contents, if needed:
00273     //buildLegend();
00274 
00275     // PENDING(kalle) Support palette
00276 
00277     Q_FOREACH( KDChart::AbstractLayoutItem* layoutItem, d->layoutItems ) {
00278         layoutItem->paint( painter );
00279     }
00280 #ifdef DEBUG_LEGEND_PAINT
00281     qDebug() << "leaving Legend::paint( QPainter* painter )";
00282 #endif
00283 }
00284 
00285 
00286 uint Legend::datasetCount() const
00287 {
00288     int modelLabelsCount = 0;
00289     int modelBrushesCount = 0;
00290     for (int i = 0; i < d->observers.size(); ++i) {
00291         DiagramObserver * obs = d->observers.at(i);
00292         modelLabelsCount  += obs->diagram()->datasetLabels().count();
00293         modelBrushesCount += obs->diagram()->datasetBrushes().count();
00294     }
00295     Q_ASSERT( modelLabelsCount == modelBrushesCount );
00296     return modelLabelsCount;
00297 }
00298 
00299 
00300 void Legend::setReferenceArea( const QWidget* area )
00301 {
00302     if( area == d->referenceArea ) return;
00303     d->referenceArea = area;
00304     setNeedRebuild();
00305 }
00306 
00307 const QWidget* Legend::referenceArea() const
00308 {
00309     //qDebug() << d->referenceArea;
00310     return (d->referenceArea ? d->referenceArea : static_cast<const QWidget*>(parent()));
00311 }
00312 
00313 
00314 AbstractDiagram* Legend::diagram() const
00315 {
00316     if( d->observers.isEmpty() )
00317         return 0;
00318     return d->observers.first()->diagram();
00319 }
00320 
00321 DiagramList Legend::diagrams() const
00322 {
00323     DiagramList list;
00324     for (int i = 0; i < d->observers.size(); ++i)
00325         list << d->observers.at(i)->diagram();
00326     return list;
00327 }
00328 
00329 ConstDiagramList Legend::constDiagrams() const
00330 {
00331     ConstDiagramList list;
00332     for (int i = 0; i < d->observers.size(); ++i)
00333         list << d->observers.at(i)->diagram();
00334     return list;
00335 }
00336 
00337 void Legend::addDiagram( AbstractDiagram* newDiagram )
00338 {
00339     if ( newDiagram )
00340     {
00341         DiagramObserver* observer = new DiagramObserver( newDiagram, this );
00342 
00343         DiagramObserver* oldObs = d->findObserverForDiagram( newDiagram );
00344         if( oldObs ){
00345             delete oldObs;
00346             d->observers[ d->observers.indexOf( oldObs ) ] = observer;
00347         }else{
00348             d->observers.append( observer );
00349         }
00350         connect( observer, SIGNAL( diagramDestroyed(AbstractDiagram*) ),
00351                         SLOT( resetDiagram(AbstractDiagram*) ));
00352         connect( observer, SIGNAL( diagramDataChanged(AbstractDiagram*) ),
00353                  SLOT( setNeedRebuild() ));
00354         connect( observer, SIGNAL( diagramDataHidden(AbstractDiagram*) ),
00355                  SLOT( setNeedRebuild() ));
00356         connect( observer, SIGNAL( diagramAttributesChanged(AbstractDiagram*) ),
00357                         SLOT( setNeedRebuild() ));
00358         setNeedRebuild();
00359     }
00360 }
00361 
00362 void Legend::removeDiagram( AbstractDiagram* oldDiagram )
00363 {
00364     if( oldDiagram ){
00365         DiagramObserver* oldObs = d->findObserverForDiagram( oldDiagram );
00366         if( oldObs ){
00367             //qDebug() << "before delete oldObs;";
00368             delete oldObs;
00369             //qDebug() << "after delete oldObs;";
00370             d->observers.removeAt( d->observers.indexOf( oldObs ) );
00371             //qDebug() << "after d->observers.removeAt()";
00372         }
00373         setNeedRebuild();
00374     }
00375 }
00376 
00377 void Legend::removeDiagrams()
00378 {
00379     for (int i = 0; i < d->observers.size(); ++i)
00380         removeDiagram( d->observers.at(i)->diagram() );
00381 }
00382 
00383 void Legend::replaceDiagram( AbstractDiagram* newDiagram,
00384                              AbstractDiagram* oldDiagram )
00385 {
00386     KDChart::AbstractDiagram* old = oldDiagram;
00387     if( ! d->observers.isEmpty() && ! old ){
00388         old = d->observers.first()->diagram();
00389         if( ! old )
00390             d->observers.removeFirst(); // first entry had a 0 diagram
00391     }
00392     if( old )
00393         removeDiagram( old );
00394     if( newDiagram )
00395         addDiagram( newDiagram );
00396 }
00397 
00398 void Legend::setDiagram( KDChart::AbstractDiagram* newDiagram )
00399 {
00400     replaceDiagram( newDiagram );
00401 }
00402 
00403 void Legend::resetDiagram( AbstractDiagram* oldDiagram )
00404 {
00405     //qDebug() << oldDiagram;
00406     removeDiagram( oldDiagram );
00407 }
00408 
00409 void Legend::setVisible( bool visible )
00410 {
00411     if( isVisible() == visible )
00412         return;
00413     QWidget::setVisible( visible );
00414     emitPositionChanged();
00415 }
00416 
00417 void Legend::setNeedRebuild()
00418 {
00419     //qDebug() << "setNeedRebuild()";
00420     buildLegend();
00421     sizeHint();
00422 }
00423 
00424 void Legend::setPosition( Position position )
00425 {
00426     if( d->position == position )
00427         return;
00428     d->position = position;
00429     emitPositionChanged();
00430 }
00431 
00432 void Legend::emitPositionChanged()
00433 {
00434     emit positionChanged( this );
00435     emit propertiesChanged();
00436 }
00437 
00438 
00439 Position Legend::position() const
00440 {
00441     return d->position;
00442 }
00443 
00444 void Legend::setAlignment( Qt::Alignment alignment )
00445 {
00446     if( d->alignment == alignment )
00447         return;
00448     d->alignment = alignment;
00449     emitPositionChanged();
00450 }
00451 
00452 Qt::Alignment Legend::alignment() const
00453 {
00454     return d->alignment;
00455 }
00456 
00457 void Legend::setFloatingPosition( const RelativePosition& relativePosition )
00458 {
00459     d->position = Position::Floating;
00460     if( d->relativePosition != relativePosition ){
00461         d->relativePosition  = relativePosition;
00462         emitPositionChanged();
00463     }
00464 }
00465 
00466 const RelativePosition Legend::floatingPosition() const
00467 {
00468     return d->relativePosition;
00469 }
00470 
00471 void Legend::setOrientation( Qt::Orientation orientation )
00472 {
00473     if( d->orientation == orientation ) return;
00474     d->orientation = orientation;
00475     setNeedRebuild();
00476     emitPositionChanged();
00477 }
00478 
00479 Qt::Orientation Legend::orientation() const
00480 {
00481     return d->orientation;
00482 }
00483 
00484 void Legend::setShowLines( bool legendShowLines )
00485 {
00486     if( d->showLines == legendShowLines ) return;
00487     d->showLines = legendShowLines;
00488     setNeedRebuild();
00489     emitPositionChanged();
00490 }
00491 
00492 bool Legend::showLines() const
00493 {
00494     return d->showLines;
00495 }
00496 
00497 void Legend::setUseAutomaticMarkerSize( bool useAutomaticMarkerSize )
00498 {
00499     d->useAutomaticMarkerSize = useAutomaticMarkerSize;
00500     setNeedRebuild();
00501     emitPositionChanged();
00502 }
00503 
00504 bool Legend::useAutomaticMarkerSize() const
00505 {
00506     return d->useAutomaticMarkerSize;
00507 }
00508 
00514 void Legend::resetTexts()
00515 {
00516     if( ! d->texts.count() ) return;
00517     d->texts.clear();
00518     setNeedRebuild();
00519 }
00520 
00521 void Legend::setText( uint dataset, const QString& text )
00522 {
00523     if( d->texts[ dataset ] == text ) return;
00524     d->texts[ dataset ] = text;
00525     setNeedRebuild();
00526 }
00527 
00528 QString Legend::text( uint dataset ) const
00529 {
00530     if( d->texts.find( dataset ) != d->texts.end() ){
00531         return d->texts[ dataset ];
00532     }else{
00533         return d->modelLabels[ dataset ];
00534     }
00535 }
00536 
00537 const QMap<uint,QString> Legend::texts() const
00538 {
00539     return d->texts;
00540 }
00541 
00542 void Legend::setColor( uint dataset, const QColor& color )
00543 {
00544     if( d->brushes[ dataset ] == color ) return;
00545     d->brushes[ dataset ] = color;
00546     setNeedRebuild();
00547     update();
00548 }
00549 
00550 void Legend::setBrush( uint dataset, const QBrush& brush )
00551 {
00552     if( d->brushes[ dataset ] == brush ) return;
00553     d->brushes[ dataset ] = brush;
00554     setNeedRebuild();
00555     update();
00556 }
00557 
00558 QBrush Legend::brush( uint dataset ) const
00559 {
00560     if( d->brushes.find( dataset ) != d->brushes.end() )
00561         return d->brushes[ dataset ];
00562     else
00563         return d->modelBrushes[ dataset ];
00564 }
00565 
00566 const QMap<uint,QBrush> Legend::brushes() const
00567 {
00568     return d->brushes;
00569 }
00570 
00571 
00572 void Legend::setBrushesFromDiagram( KDChart::AbstractDiagram* diagram )
00573 {
00574     bool bChangesDone = false;
00575     QList<QBrush> datasetBrushes = diagram->datasetBrushes();
00576     for( int i = 0; i < datasetBrushes.count(); i++ ){
00577         if( d->brushes[ i ] != datasetBrushes[ i ] ){
00578             d->brushes[ i ]  = datasetBrushes[ i ];
00579             bChangesDone = true;
00580         }
00581     }
00582     if( bChangesDone ) {
00583         setNeedRebuild();
00584         update();
00585     }
00586 }
00587 
00588 
00589 void Legend::setPen( uint dataset, const QPen& pen )
00590 {
00591     if( d->pens[dataset] == pen ) return;
00592     d->pens[dataset] = pen;
00593     setNeedRebuild();
00594     update();
00595 }
00596 
00597 QPen Legend::pen( uint dataset ) const
00598 {
00599     if( d->pens.find( dataset ) != d->pens.end() )
00600         return d->pens[dataset];
00601     else
00602         return d->modelPens[ dataset ];
00603 }
00604 
00605 const QMap<uint,QPen> Legend::pens() const
00606 {
00607     return d->pens;
00608 }
00609 
00610 
00611 void Legend::setMarkerAttributes( uint dataset, const MarkerAttributes& markerAttributes )
00612 {
00613     if( d->markerAttributes[dataset] == markerAttributes ) return;
00614     d->markerAttributes[ dataset ] = markerAttributes;
00615     setNeedRebuild();
00616     update();
00617 }
00618 
00619 MarkerAttributes Legend::markerAttributes( uint dataset ) const
00620 {
00621     if( d->markerAttributes.find( dataset ) != d->markerAttributes.end() )
00622         return d->markerAttributes[ dataset ];
00623     else if ( static_cast<uint>( d->modelMarkers.count() ) > dataset )
00624         return d->modelMarkers[ dataset ];
00625     return MarkerAttributes();
00626 }
00627 
00628 const QMap<uint, MarkerAttributes> Legend::markerAttributes() const
00629 {
00630     return d->markerAttributes;
00631 }
00632 
00633 
00634 void Legend::setTextAttributes( const TextAttributes &a )
00635 {
00636     if( d->textAttributes == a ) return;
00637     d->textAttributes = a;
00638     setNeedRebuild();
00639 }
00640 
00641 TextAttributes Legend::textAttributes() const
00642 {
00643     return d->textAttributes;
00644 }
00645 
00646 void Legend::setTitleText( const QString& text )
00647 {
00648     if( d->titleText == text ) return;
00649     d->titleText = text;
00650     setNeedRebuild();
00651 }
00652 
00653 QString Legend::titleText() const
00654 {
00655     return d->titleText;
00656 }
00657 
00658 void Legend::setTitleTextAttributes( const TextAttributes &a )
00659 {
00660     if( d->titleTextAttributes == a ) return;
00661     d->titleTextAttributes = a;
00662     setNeedRebuild();
00663 }
00664 
00665 TextAttributes Legend::titleTextAttributes() const
00666 {
00667     return d->titleTextAttributes;
00668 }
00669 
00670 void Legend::forceRebuild()
00671 {
00672 #ifdef DEBUG_LEGEND_PAINT
00673     qDebug() << "entering Legend::forceRebuild()";
00674 #endif
00675     //setSpacing(d->layout->spacing());
00676     buildLegend();
00677 #ifdef DEBUG_LEGEND_PAINT
00678     qDebug() << "leaving Legend::forceRebuild()";
00679 #endif
00680 }
00681 
00682 void Legend::setSpacing( uint space )
00683 {
00684     if( d->spacing == space && d->layout->spacing() == static_cast<int>(space) ) return;
00685     d->spacing = space;
00686     d->layout->setSpacing( space );
00687     setNeedRebuild();
00688 }
00689 
00690 uint Legend::spacing() const
00691 {
00692     return d->spacing;
00693 }
00694 
00695 void Legend::setDefaultColors()
00696 {
00697     setColor(  0, Qt::red );
00698     setColor(  1, Qt::green );
00699     setColor(  2, Qt::blue );
00700     setColor(  3, Qt::cyan );
00701     setColor(  4, Qt::magenta );
00702     setColor(  5, Qt::yellow );
00703     setColor(  6, Qt::darkRed );
00704     setColor(  7, Qt::darkGreen );
00705     setColor(  8, Qt::darkBlue );
00706     setColor(  9, Qt::darkCyan );
00707     setColor( 10, Qt::darkMagenta );
00708     setColor( 11, Qt::darkYellow );
00709 }
00710 
00711 void Legend::setRainbowColors()
00712 {
00713     setColor(  0, QColor(255,  0,196) );
00714     setColor(  1, QColor(255,  0, 96) );
00715     setColor(  2, QColor(255, 128,64) );
00716     setColor(  3, Qt::yellow );
00717     setColor(  4, Qt::green );
00718     setColor(  5, Qt::cyan );
00719     setColor(  6, QColor( 96, 96,255) );
00720     setColor(  7, QColor(160,  0,255) );
00721     for( int i = 8; i < 16; ++i )
00722         setColor( i, brush( i - 8 ).color().light() );
00723 }
00724 
00725 void Legend::setSubduedColors( bool ordered )
00726 {
00727 static const int NUM_SUBDUEDCOLORS = 18;
00728 static const QColor SUBDUEDCOLORS[ NUM_SUBDUEDCOLORS ] = {
00729     QColor( 0xe0,0x7f,0x70 ),
00730     QColor( 0xe2,0xa5,0x6f ),
00731     QColor( 0xe0,0xc9,0x70 ),
00732     QColor( 0xd1,0xe0,0x70 ),
00733     QColor( 0xac,0xe0,0x70 ),
00734     QColor( 0x86,0xe0,0x70 ),
00735     QColor( 0x70,0xe0,0x7f ),
00736     QColor( 0x70,0xe0,0xa4 ),
00737     QColor( 0x70,0xe0,0xc9 ),
00738     QColor( 0x70,0xd1,0xe0 ),
00739     QColor( 0x70,0xac,0xe0 ),
00740     QColor( 0x70,0x86,0xe0 ),
00741     QColor( 0x7f,0x70,0xe0 ),
00742     QColor( 0xa4,0x70,0xe0 ),
00743     QColor( 0xc9,0x70,0xe0 ),
00744     QColor( 0xe0,0x70,0xd1 ),
00745     QColor( 0xe0,0x70,0xac ),
00746     QColor( 0xe0,0x70,0x86 ),
00747 };
00748     if( ordered )
00749         for(int i=0; i<NUM_SUBDUEDCOLORS; ++i)
00750             setColor( i, SUBDUEDCOLORS[i] );
00751     else{
00752         setColor( 0, SUBDUEDCOLORS[ 0] );
00753         setColor( 1, SUBDUEDCOLORS[ 5] );
00754         setColor( 2, SUBDUEDCOLORS[10] );
00755         setColor( 3, SUBDUEDCOLORS[15] );
00756         setColor( 4, SUBDUEDCOLORS[ 2] );
00757         setColor( 5, SUBDUEDCOLORS[ 7] );
00758         setColor( 6, SUBDUEDCOLORS[12] );
00759         setColor( 7, SUBDUEDCOLORS[17] );
00760         setColor( 8, SUBDUEDCOLORS[ 4] );
00761         setColor( 9, SUBDUEDCOLORS[ 9] );
00762         setColor(10, SUBDUEDCOLORS[14] );
00763         setColor(11, SUBDUEDCOLORS[ 1] );
00764         setColor(12, SUBDUEDCOLORS[ 6] );
00765         setColor(13, SUBDUEDCOLORS[11] );
00766         setColor(14, SUBDUEDCOLORS[16] );
00767         setColor(15, SUBDUEDCOLORS[ 3] );
00768         setColor(16, SUBDUEDCOLORS[ 8] );
00769         setColor(17, SUBDUEDCOLORS[13] );
00770     }
00771 }
00772 
00773 void Legend::resizeEvent ( QResizeEvent * event )
00774 {
00775     Q_UNUSED( event );
00776 #ifdef DEBUG_LEGEND_PAINT
00777     qDebug() << "Legend::resizeEvent() called";
00778 #endif
00779     forceRebuild();
00780     sizeHint();
00781     QTimer::singleShot(0, this, SLOT(emitPositionChanged()));
00782 }
00783 
00784 void Legend::buildLegend()
00785 {
00786     /*
00787     if( !d->needRebuild ) {
00788 #ifdef DEBUG_LEGEND_PAINT
00789         qDebug() << "leaving Legend::buildLegend() with NO action (was already build)";
00790 #endif
00791         // Note: We do *not* need to send positionChanged here,
00792         //       because we send it in the resizeEvent, so layouting
00793         //       is done at the right time.
00794         return;
00795     }
00796 #ifdef DEBUG_LEGEND_PAINT
00797     qDebug() << "entering Legend::buildLegend() **********************************";
00798 #endif
00799     d->needRebuild = false;
00800     */
00801 
00802     Q_FOREACH( QLayoutItem* layoutItem, d->layoutItems ) {
00803         d->layout->removeItem( layoutItem );
00804     }
00805     qDeleteAll( d->layoutItems );
00806     d->layoutItems.clear();
00807 
00808     if( orientation() == Qt::Vertical ) {
00809         d->layout->setColumnStretch( 4, 1 );
00810     } else {
00811         d->layout->setColumnStretch( 4, 0 );
00812     }
00813 
00814     d->modelLabels.clear();
00815     d->modelBrushes.clear();
00816     d->modelPens.clear();
00817     d->modelMarkers.clear();
00818     // retrieve the diagrams' settings for all non-hidden datasets
00819     for (int i = 0; i < d->observers.size(); ++i){
00820         const AbstractDiagram* diagram = d->observers.at(i)->diagram();
00821         if( diagram ){
00822             //qDebug() << "accessing" << diagram;
00823             const QStringList             diagramLabels(  diagram->datasetLabels()  );
00824             const QList<QBrush>           diagramBrushes( diagram->datasetBrushes() );
00825             const QList<QPen>             diagramPens(    diagram->datasetPens()    );
00826             const QList<MarkerAttributes> diagramMarkers( diagram->datasetMarkers() );
00827             for ( int dataset = 0; dataset < diagramLabels.count(); dataset++ ) {
00828                 // only show the label if the diagrams is NOT having the dataset set to hidden
00829                 if( ! diagram->isHidden( dataset ) ){
00830                     d->modelLabels  += diagramLabels[   dataset ];
00831                     d->modelBrushes += diagramBrushes[  dataset ];
00832                     d->modelPens    += diagramPens[     dataset ];
00833                     d->modelMarkers += diagramMarkers[  dataset ];
00834                 }
00835             }
00836         }
00837     }
00838 
00839     Q_ASSERT( d->modelLabels.count() == d->modelBrushes.count() );
00840 
00841     // legend caption
00842     if( !titleText().isEmpty() && titleTextAttributes().isVisible() ) {
00843         // PENDING(kalle) Other properties!
00844         KDChart::TextLayoutItem* titleItem =
00845             new KDChart::TextLayoutItem( titleText(),
00846                 titleTextAttributes(),
00847                 referenceArea(),
00848                 (orientation() == Qt::Vertical)
00849                 ? KDChartEnums::MeasureOrientationMinimum
00850                 : KDChartEnums::MeasureOrientationHorizontal,
00851                 Qt::AlignCenter );
00852         titleItem->setParentWidget( this );
00853 
00854         d->layoutItems << titleItem;
00855         if( orientation() == Qt::Vertical )
00856             d->layout->addItem( titleItem, 0, 0, 1, 5, Qt::AlignCenter );
00857         else
00858             d->layout->addItem( titleItem, 0, 0, 1, d->modelLabels.count() ? (d->modelLabels.count()*4) : 1, Qt::AlignCenter );
00859 
00860         // The line between the title and the legend items, if any.
00861         if( showLines() && d->modelLabels.count() ) {
00862             KDChart::HorizontalLineLayoutItem* lineItem = new KDChart::HorizontalLineLayoutItem();
00863             d->layoutItems << lineItem;
00864             if( orientation() == Qt::Vertical )
00865                 d->layout->addItem( lineItem, 1, 0, 1, 5, Qt::AlignCenter );
00866             else
00867                 d->layout->addItem( lineItem, 1, 0, 1, d->modelLabels.count()*4, Qt::AlignCenter );
00868         }
00869     }
00870 
00871     const KDChartEnums::MeasureOrientation orient =
00872             (orientation() == Qt::Vertical)
00873             ? KDChartEnums::MeasureOrientationMinimum
00874             : KDChartEnums::MeasureOrientationHorizontal;
00875     const TextAttributes labelAttrs( textAttributes() );
00876     const qreal fontHeight = labelAttrs.calculatedFontSize( referenceArea(), orient );
00877     const LegendStyle style = legendStyle();
00878     //qDebug() << "fontHeight:" << fontHeight;
00879 
00880     const bool bShowMarkers = (style != LinesOnly);
00881 
00882     QSizeF maxMarkersSize(1.0, 1.0);
00883     QVector <MarkerAttributes> markerAttrs( d->modelLabels.count() );
00884     if( bShowMarkers ){
00885         for ( int dataset = 0; dataset < d->modelLabels.count(); ++dataset ) {
00886             markerAttrs[dataset] = markerAttributes( dataset );
00887             QSizeF siz;
00888             if( useAutomaticMarkerSize() ||
00889                 ! markerAttrs[dataset].markerSize().isValid() )
00890             {
00891                 siz = QSizeF(fontHeight, fontHeight);
00892                 markerAttrs[dataset].setMarkerSize( siz );
00893             }else{
00894                 siz = markerAttrs[dataset].markerSize();
00895             }
00896             maxMarkersSize =
00897                     QSizeF(qMax(maxMarkersSize.width(),  siz.width()),
00898                            qMax(maxMarkersSize.height(), siz.height()));
00899         }
00900     }
00901 
00902     // If we show a marker on a line, we paint it after 4 pixels
00903     // of the line have been painted. This allows to see the line style
00904     // at the right side of the marker without the line needing to
00905     // be too long.
00906     // (having the marker in the middle of the line would require longer lines)
00907     const int markerOffsOnLine = 8;
00908 
00909     int maxLineLength = 18;
00910     {
00911         bool hasComplexPenStyle = false;
00912         for ( int dataset = 0; dataset < d->modelLabels.count(); ++dataset ){
00913             const QPen pn = pen(dataset);
00914             const Qt::PenStyle ps = pn.style();
00915             if( ps != Qt::NoPen ){
00916                 maxLineLength = qMax( pn.width() * 18, maxLineLength );
00917                 if( ps != Qt::SolidLine )
00918                     hasComplexPenStyle = true;
00919             }
00920         }
00921         if( hasComplexPenStyle && bShowMarkers )
00922             maxLineLength =
00923                     maxLineLength + markerOffsOnLine +
00924                     static_cast<int>(maxMarkersSize.width());
00925     }
00926 
00927     for ( int dataset = 0; dataset < d->modelLabels.count(); ++dataset ) {
00928         KDChart::AbstractLayoutItem* markerLineItem = 0;
00929         switch( style ){
00930             case( MarkersOnly ):
00931                 markerLineItem = new KDChart::MarkerLayoutItem(
00932                         diagram(),
00933                         markerAttrs[dataset],
00934                         brush( dataset ),
00935                         markerAttrs[dataset].pen(),
00936                         Qt::AlignLeft );
00937                 break;
00938             case( LinesOnly ):
00939                 markerLineItem = new KDChart::LineLayoutItem(
00940                         diagram(),
00941                         maxLineLength,
00942                         pen( dataset ),
00943                         Qt::AlignCenter );
00944                 break;
00945             case( MarkersAndLines ):
00946                 markerLineItem = new KDChart::LineWithMarkerLayoutItem(
00947                         diagram(),
00948                         maxLineLength,
00949                         pen( dataset ),
00950                         markerOffsOnLine,
00951                         markerAttrs[dataset],
00952                         brush( dataset ),
00953                         markerAttrs[dataset].pen(),
00954                         Qt::AlignCenter );
00955                 break;
00956             default:
00957                 Q_ASSERT( false ); // all styles need to be handled
00958         }
00959         if( markerLineItem ){
00960             d->layoutItems << markerLineItem;
00961             if( orientation() == Qt::Vertical )
00962                 d->layout->addItem( markerLineItem,
00963                                     dataset*2+2, // first row is title, second is line
00964                                     1,
00965                                     1, 1, Qt::AlignCenter );
00966             else
00967                 d->layout->addItem( markerLineItem,
00968                                     2, // all in row two
00969                                     dataset*4 );
00970         }
00971 
00972         // PENDING(kalle) Other properties!
00973         KDChart::TextLayoutItem* labelItem =
00974             new KDChart::TextLayoutItem( text( dataset ),
00975                 labelAttrs,
00976                 referenceArea(), orient,
00977                 Qt::AlignLeft );
00978         labelItem->setParentWidget( this );
00979 
00980         d->layoutItems << labelItem;
00981         if( orientation() == Qt::Vertical )
00982             d->layout->addItem( labelItem,
00983                                 dataset*2+2, // first row is title, second is line
00984                                 3 );
00985         else
00986             d->layout->addItem( labelItem,
00987                                 2, // all in row two
00988                                 dataset*4+1 );
00989 
00990         // horizontal lines (only in vertical mode, and not after the last item)
00991         if( orientation() == Qt::Vertical && showLines() && dataset != d->modelLabels.count()-1 ) {
00992             KDChart::HorizontalLineLayoutItem* lineItem = new KDChart::HorizontalLineLayoutItem();
00993             d->layoutItems << lineItem;
00994             d->layout->addItem( lineItem,
00995                                 dataset*2+1+2,
00996                                 0,
00997                                 1, 5, Qt::AlignCenter );
00998         }
00999 
01000         // vertical lines (only in horizontal mode, and not after the last item)
01001         if( orientation() == Qt::Horizontal && showLines() && dataset != d->modelLabels.count()-1 ) {
01002             KDChart::VerticalLineLayoutItem* lineItem = new KDChart::VerticalLineLayoutItem();
01003             d->layoutItems << lineItem;
01004             d->layout->addItem( lineItem,
01005                                 2, // all in row two
01006                                 style == MarkersAndLines ? dataset*4+3 : dataset*4+2 ,
01007                                 1, 1, Qt::AlignCenter );
01008         }
01009 
01010         if( orientation() != Qt::Vertical ) { // Horizontal needs a spacer
01011             d->layout->addItem( new QSpacerItem( spacing(), 1 ),
01012                                 2, // all in row two
01013                                 dataset*4+3 );
01014         }
01015     }
01016 
01017     // vertical line (only in vertical mode)
01018     if( orientation() == Qt::Vertical && showLines() && d->modelLabels.count() ) {
01019         KDChart::VerticalLineLayoutItem* lineItem = new KDChart::VerticalLineLayoutItem();
01020         d->layoutItems << lineItem;
01021         d->layout->addItem( lineItem, 2, 2, d->modelLabels.count()*2, 1 );
01022     }
01023 
01024     // This line is absolutely necessary, otherwise: #2516.
01025     activateTheLayout();
01026 
01027     emit propertiesChanged();
01028     //emit positionChanged( this );
01029     //emitPositionChanged();
01030 #ifdef DEBUG_LEGEND_PAINT
01031     qDebug() << "leaving Legend::buildLegend()";
01032 #endif
01033 }

Generated on Mon Sep 17 16:16:50 2007 for KD Chart 2 by  doxygen 1.5.1