Main Page | Namespace List | Class Hierarchy | Alphabetical List | Class List | File List | Namespace Members | Class Members | File Members | Related Pages

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 

Generated on Thu May 10 11:06:25 2007 for KD Chart 2 by doxygen 1.3.6