00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022
00023 #include "KDChartLegend.h"
00024 #include "KDChartLegend_p.h"
00025 #include <KDChartTextAttributes.h>
00026 #include <KDChartMarkerAttributes.h>
00027 #include <QFont>
00028 #include <QPainter>
00029 #include <QTextTableCell>
00030 #include <QTextCursor>
00031 #include <QTextCharFormat>
00032 #include <QTextDocumentFragment>
00033 #include <QTimer>
00034 #include <QAbstractTextDocumentLayout>
00035 #include <QtDebug>
00036 #include <QLabel>
00037 #include <KDChartAbstractDiagram.h>
00038 #include "KDTextDocument.h"
00039 #include <KDChartDiagramObserver.h>
00040 #include <QGridLayout>
00041 #include "KDChartLayoutItems.h"
00042
00043 #include <KDABLibFakes>
00044
00045 using namespace KDChart;
00046
00047 Legend::Private::Private() :
00048 referenceArea(0),
00049 position( Position::East ),
00050 alignment( Qt::AlignCenter ),
00051 textAlignment( Qt::AlignCenter ),
00052 relativePosition( RelativePosition() ),
00053 orientation( Qt::Vertical ),
00054 order( Qt::AscendingOrder ),
00055 showLines( false ),
00056 texts(),
00057 textAttributes(),
00058 titleText( QObject::tr( "Legend" ) ),
00059 titleTextAttributes(),
00060 spacing( 1 ),
00061 useAutomaticMarkerSize( true ),
00062 legendStyle( MarkersOnly )
00063
00064 {
00065
00066
00067 relativePosition.setReferencePoints( PositionPoints( QPointF( 0.0, 0.0 ) ) );
00068 relativePosition.setReferencePosition( Position::NorthWest );
00069 relativePosition.setAlignment( Qt::AlignTop | Qt::AlignLeft );
00070 relativePosition.setHorizontalPadding( KDChart::Measure( 4.0, KDChartEnums::MeasureCalculationModeAbsolute ) );
00071 relativePosition.setVerticalPadding( KDChart::Measure( 4.0, KDChartEnums::MeasureCalculationModeAbsolute ) );
00072 }
00073
00074 Legend::Private::~Private()
00075 {
00076
00077 }
00078
00079
00080
00081 #define d d_func()
00082
00083
00084 Legend::Legend( QWidget* parent ) :
00085 AbstractAreaWidget( new Private(), parent )
00086 {
00087 d->referenceArea = parent;
00088 init();
00089 }
00090
00091 Legend::Legend( KDChart::AbstractDiagram* diagram, QWidget* parent ) :
00092 AbstractAreaWidget( new Private(), parent )
00093 {
00094 d->referenceArea = parent;
00095 init();
00096 setDiagram( diagram );
00097 }
00098
00099 Legend::~Legend()
00100 {
00101 emit destroyedLegend( this );
00102 }
00103
00104 void Legend::init()
00105 {
00106 setSizePolicy( QSizePolicy::Fixed, QSizePolicy::Fixed );
00107
00108 d->layout = new QGridLayout( this );
00109 d->layout->setMargin( 2 );
00110 d->layout->setSpacing( d->spacing );
00111
00112
00113 const Measure normalFontSizeTitle( 12, KDChartEnums::MeasureCalculationModeAbsolute );
00114 const Measure normalFontSizeLabels( 10, KDChartEnums::MeasureCalculationModeAbsolute );
00115 const Measure minimalFontSize( 4, KDChartEnums::MeasureCalculationModeAbsolute );
00116
00117 TextAttributes textAttrs;
00118 textAttrs.setPen( QPen( Qt::black ) );
00119 textAttrs.setFont( QFont( QLatin1String( "helvetica" ), 10, QFont::Normal, false ) );
00120 textAttrs.setFontSize( normalFontSizeLabels );
00121 textAttrs.setMinimalFontSize( minimalFontSize );
00122 setTextAttributes( textAttrs );
00123
00124 TextAttributes titleTextAttrs;
00125 titleTextAttrs.setPen( QPen( Qt::black ) );
00126 titleTextAttrs.setFont( QFont( QLatin1String( "helvetica" ), 12, QFont::Bold, false ) );
00127 titleTextAttrs.setFontSize( normalFontSizeTitle );
00128 titleTextAttrs.setMinimalFontSize( minimalFontSize );
00129 setTitleTextAttributes( titleTextAttrs );
00130
00131 FrameAttributes frameAttrs;
00132 frameAttrs.setVisible( true );
00133 frameAttrs.setPen( QPen( Qt::black ) );
00134 frameAttrs.setPadding( 1 );
00135 setFrameAttributes( frameAttrs );
00136
00137 d->position = Position::NorthEast;
00138 d->alignment = Qt::AlignCenter;
00139 }
00140
00141
00142 QSize Legend::minimumSizeHint() const
00143 {
00144 return sizeHint();
00145 }
00146
00147
00148
00149 QSize Legend::sizeHint() const
00150 {
00151 #ifdef DEBUG_LEGEND_PAINT
00152 qDebug() << "Legend::sizeHint() started";
00153 #endif
00154 Q_FOREACH( KDChart::AbstractLayoutItem* layoutItem, d->layoutItems ) {
00155 layoutItem->sizeHint();
00156 }
00157 return AbstractAreaWidget::sizeHint();
00158 }
00159
00160 void Legend::needSizeHint()
00161 {
00162
00163
00164 buildLegend();
00165 }
00166
00167 void Legend::resizeLayout( const QSize& size )
00168 {
00169 #ifdef DEBUG_LEGEND_PAINT
00170 qDebug() << "Legend::resizeLayout started";
00171 #endif
00172 if( d->layout ){
00173 d->layout->setGeometry( QRect(QPoint(0,0), size) );
00174 activateTheLayout();
00175 }
00176 #ifdef DEBUG_LEGEND_PAINT
00177 qDebug() << "Legend::resizeLayout done";
00178 #endif
00179 }
00180
00181 void Legend::activateTheLayout()
00182 {
00183 if( d->layout && d->layout->parent() )
00184 d->layout->activate();
00185 }
00186
00187
00188 void Legend::setLegendStyle( LegendStyle style )
00189 {
00190 if( d->legendStyle == style ) return;
00191 d->legendStyle = style;
00192 setNeedRebuild();
00193 }
00194
00195 Legend::LegendStyle Legend::legendStyle() const
00196 {
00197 return d->legendStyle;
00198 }
00199
00203 Legend* Legend::clone() const
00204 {
00205 Legend* legend = new Legend( new Private( *d ), 0 );
00206 legend->setTextAttributes( textAttributes() );
00207 legend->setTitleTextAttributes( titleTextAttributes() );
00208 legend->setFrameAttributes( frameAttributes() );
00209 legend->setUseAutomaticMarkerSize( useAutomaticMarkerSize() );
00210 legend->setPosition( position() );
00211 legend->setAlignment( alignment() );
00212 legend->setTextAlignment( textAlignment() );
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
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() << (textAlignment() == other->textAlignment());
00231 qDebug() << (floatingPosition() == other->floatingPosition());
00232 qDebug() << (orientation() == other->orientation());
00233 qDebug() << (showLines() == other->showLines());
00234 qDebug() << (texts() == other->texts());
00235 qDebug() << (brushes() == other->brushes());
00236 qDebug() << (pens() == other->pens());
00237 qDebug() << (markerAttributes() == other->markerAttributes());
00238 qDebug() << (useAutomaticMarkerSize() == other->useAutomaticMarkerSize());
00239 qDebug() << (textAttributes() == other->textAttributes());
00240 qDebug() << (titleText() == other->titleText());
00241 qDebug() << (titleTextAttributes() == other->titleTextAttributes());
00242 qDebug() << (spacing() == other->spacing());
00243 qDebug() << (legendStyle() == other->legendStyle());
00244
00245 return ( static_cast<const AbstractAreaBase*>(this)->compare( other ) ) &&
00246 (isVisible() == other->isVisible()) &&
00247 (position() == other->position()) &&
00248 (alignment() == other->alignment())&&
00249 (textAlignment() == other->textAlignment())&&
00250 (floatingPosition() == other->floatingPosition()) &&
00251 (orientation() == other->orientation())&&
00252 (showLines() == other->showLines())&&
00253 (texts() == other->texts())&&
00254 (brushes() == other->brushes())&&
00255 (pens() == other->pens())&&
00256 (markerAttributes() == other->markerAttributes())&&
00257 (useAutomaticMarkerSize() == other->useAutomaticMarkerSize()) &&
00258 (textAttributes() == other->textAttributes()) &&
00259 (titleText() == other->titleText())&&
00260 (titleTextAttributes() == other->titleTextAttributes()) &&
00261 (spacing() == other->spacing()) &&
00262 (legendStyle() == other->legendStyle());
00263 }
00264
00265
00266 void Legend::paint( QPainter* painter )
00267 {
00268 #ifdef DEBUG_LEGEND_PAINT
00269 qDebug() << "entering Legend::paint( QPainter* painter )";
00270 #endif
00271
00272 if( ! diagram() ) return;
00273
00274
00275
00276
00277
00278
00279 Q_FOREACH( KDChart::AbstractLayoutItem* layoutItem, d->layoutItems ) {
00280 layoutItem->paint( painter );
00281 }
00282 #ifdef DEBUG_LEGEND_PAINT
00283 qDebug() << "leaving Legend::paint( QPainter* painter )";
00284 #endif
00285 }
00286
00287
00288 uint Legend::datasetCount() const
00289 {
00290 int modelLabelsCount = 0;
00291 int modelBrushesCount = 0;
00292 for (int i = 0; i < d->observers.size(); ++i) {
00293 DiagramObserver * obs = d->observers.at(i);
00294 modelLabelsCount += obs->diagram()->datasetLabels().count();
00295 modelBrushesCount += obs->diagram()->datasetBrushes().count();
00296 }
00297 Q_ASSERT( modelLabelsCount == modelBrushesCount );
00298 return modelLabelsCount;
00299 }
00300
00301
00302 void Legend::setReferenceArea( const QWidget* area )
00303 {
00304 if( area == d->referenceArea ) return;
00305 d->referenceArea = area;
00306 setNeedRebuild();
00307 }
00308
00309 const QWidget* Legend::referenceArea() const
00310 {
00311
00312 return (d->referenceArea ? d->referenceArea : static_cast<const QWidget*>(parent()));
00313 }
00314
00315
00316 AbstractDiagram* Legend::diagram() const
00317 {
00318 if( d->observers.isEmpty() )
00319 return 0;
00320 return d->observers.first()->diagram();
00321 }
00322
00323 DiagramList Legend::diagrams() const
00324 {
00325 DiagramList list;
00326 for (int i = 0; i < d->observers.size(); ++i)
00327 list << d->observers.at(i)->diagram();
00328 return list;
00329 }
00330
00331 ConstDiagramList Legend::constDiagrams() const
00332 {
00333 ConstDiagramList list;
00334 for (int i = 0; i < d->observers.size(); ++i)
00335 list << d->observers.at(i)->diagram();
00336 return list;
00337 }
00338
00339 void Legend::addDiagram( AbstractDiagram* newDiagram )
00340 {
00341 if ( newDiagram )
00342 {
00343 DiagramObserver* observer = new DiagramObserver( newDiagram, this );
00344
00345 DiagramObserver* oldObs = d->findObserverForDiagram( newDiagram );
00346 if( oldObs ){
00347 delete oldObs;
00348 d->observers[ d->observers.indexOf( oldObs ) ] = observer;
00349 }else{
00350 d->observers.append( observer );
00351 }
00352 connect( observer, SIGNAL( diagramAboutToBeDestroyed(AbstractDiagram*) ),
00353 SLOT( resetDiagram(AbstractDiagram*) ));
00354 connect( observer, SIGNAL( diagramDataChanged(AbstractDiagram*) ),
00355 SLOT( setNeedRebuild() ));
00356 connect( observer, SIGNAL( diagramDataHidden(AbstractDiagram*) ),
00357 SLOT( setNeedRebuild() ));
00358 connect( observer, SIGNAL( diagramAttributesChanged(AbstractDiagram*) ),
00359 SLOT( setNeedRebuild() ));
00360 setNeedRebuild();
00361 }
00362 }
00363
00364 void Legend::removeDiagram( AbstractDiagram* oldDiagram )
00365 {
00366 int datasetBrushOffset = 0;
00367 QList<AbstractDiagram*> diagrams = this->diagrams();
00368 for(int i =0; i <diagrams.count(); i++)
00369 {
00370 if(diagrams.at(i) == oldDiagram)
00371 {
00372 for( int i = 0; i < oldDiagram->datasetBrushes().count(); i++ ){
00373 d->brushes.remove(datasetBrushOffset + i);
00374 d->texts.remove(datasetBrushOffset + i);
00375 }
00376 for( int i = 0; i < oldDiagram->datasetPens().count(); i++ ){
00377 d->pens.remove(datasetBrushOffset + i);
00378 }
00379 break;
00380 }
00381 datasetBrushOffset += diagrams.at(i)->datasetBrushes().count();
00382 }
00383
00384 if( oldDiagram ){
00385 DiagramObserver* oldObs = d->findObserverForDiagram( oldDiagram );
00386 if( oldObs ){
00387
00388 delete oldObs;
00389
00390 d->observers.removeAt( d->observers.indexOf( oldObs ) );
00391
00392 }
00393 setNeedRebuild();
00394 }
00395 }
00396
00397 void Legend::removeDiagrams()
00398 {
00399 for (int i = 0; i < d->observers.size(); ++i)
00400 removeDiagram( d->observers.at(i)->diagram() );
00401 }
00402
00403 void Legend::replaceDiagram( AbstractDiagram* newDiagram,
00404 AbstractDiagram* oldDiagram )
00405 {
00406 KDChart::AbstractDiagram* old = oldDiagram;
00407 if( ! d->observers.isEmpty() && ! old ){
00408 old = d->observers.first()->diagram();
00409 if( ! old )
00410 d->observers.removeFirst();
00411 }
00412 if( old )
00413 removeDiagram( old );
00414 if( newDiagram )
00415 addDiagram( newDiagram );
00416 }
00417
00418 uint Legend::dataSetOffset(KDChart::AbstractDiagram* diagram)
00419 {
00420 uint offset = 0;
00421
00422 for (int i = 0; i < d->observers.count(); ++i)
00423 {
00424 if(d->observers.at(i)->diagram() == diagram)
00425 return offset;
00426
00427 KDChart::AbstractDiagram* diagram = d->observers.at(i)->diagram();
00428 if(!diagram->model())
00429 continue;
00430
00431 offset = offset + diagram->model()->columnCount();
00432 }
00433
00434 return offset;
00435 }
00436
00437 void Legend::setDiagram( KDChart::AbstractDiagram* newDiagram )
00438 {
00439 replaceDiagram( newDiagram );
00440 }
00441
00442 void Legend::resetDiagram( AbstractDiagram* oldDiagram )
00443 {
00444
00445 removeDiagram( oldDiagram );
00446 }
00447
00448 void Legend::setVisible( bool visible )
00449 {
00450 if( isVisible() == visible )
00451 return;
00452 QWidget::setVisible( visible );
00453 emitPositionChanged();
00454 }
00455
00456 void Legend::setNeedRebuild()
00457 {
00458
00459 buildLegend();
00460 sizeHint();
00461 }
00462
00463 void Legend::setPosition( Position position )
00464 {
00465 if( d->position == position )
00466 return;
00467 d->position = position;
00468 emitPositionChanged();
00469 }
00470
00471 void Legend::emitPositionChanged()
00472 {
00473 emit positionChanged( this );
00474 emit propertiesChanged();
00475 }
00476
00477
00478 Position Legend::position() const
00479 {
00480 return d->position;
00481 }
00482
00483 void Legend::setAlignment( Qt::Alignment alignment )
00484 {
00485 if( d->alignment == alignment )
00486 return;
00487 d->alignment = alignment;
00488 emitPositionChanged();
00489 }
00490
00491 Qt::Alignment Legend::alignment() const
00492 {
00493 return d->alignment;
00494 }
00495
00496 void Legend::setTextAlignment( Qt::Alignment alignment )
00497 {
00498 if( d->textAlignment == alignment )
00499 return;
00500 d->textAlignment = alignment;
00501 emitPositionChanged();
00502 }
00503
00504 Qt::Alignment Legend::textAlignment() const
00505 {
00506 return d->textAlignment;
00507 }
00508
00509 void Legend::setFloatingPosition( const RelativePosition& relativePosition )
00510 {
00511 d->position = Position::Floating;
00512 if( d->relativePosition != relativePosition ){
00513 d->relativePosition = relativePosition;
00514 emitPositionChanged();
00515 }
00516 }
00517
00518 const RelativePosition Legend::floatingPosition() const
00519 {
00520 return d->relativePosition;
00521 }
00522
00523 void Legend::setOrientation( Qt::Orientation orientation )
00524 {
00525 if( d->orientation == orientation ) return;
00526 d->orientation = orientation;
00527 setNeedRebuild();
00528 emitPositionChanged();
00529 }
00530
00531 Qt::Orientation Legend::orientation() const
00532 {
00533 return d->orientation;
00534 }
00535
00536 void Legend::setSortOrder( Qt::SortOrder order )
00537 {
00538 if( d->order == order )
00539 return;
00540 d->order = order;
00541 setNeedRebuild();
00542 emitPositionChanged();
00543 }
00544
00545 Qt::SortOrder Legend::sortOrder() const
00546 {
00547 return d->order;
00548 }
00549
00550 void Legend::setShowLines( bool legendShowLines )
00551 {
00552 if( d->showLines == legendShowLines ) return;
00553 d->showLines = legendShowLines;
00554 setNeedRebuild();
00555 emitPositionChanged();
00556 }
00557
00558 bool Legend::showLines() const
00559 {
00560 return d->showLines;
00561 }
00562
00563 void Legend::setUseAutomaticMarkerSize( bool useAutomaticMarkerSize )
00564 {
00565 d->useAutomaticMarkerSize = useAutomaticMarkerSize;
00566 setNeedRebuild();
00567 emitPositionChanged();
00568 }
00569
00570 bool Legend::useAutomaticMarkerSize() const
00571 {
00572 return d->useAutomaticMarkerSize;
00573 }
00574
00580 void Legend::resetTexts()
00581 {
00582 if( ! d->texts.count() ) return;
00583 d->texts.clear();
00584 setNeedRebuild();
00585 }
00586
00587 void Legend::setText( uint dataset, const QString& text )
00588 {
00589 if( d->texts[ dataset ] == text ) return;
00590 d->texts[ dataset ] = text;
00591 setNeedRebuild();
00592 }
00593
00594 QString Legend::text( uint dataset ) const
00595 {
00596 if( d->texts.find( dataset ) != d->texts.end() ){
00597 return d->texts[ dataset ];
00598 }else{
00599 return d->modelLabels[ dataset ];
00600 }
00601 }
00602
00603 const QMap<uint,QString> Legend::texts() const
00604 {
00605 return d->texts;
00606 }
00607
00608 void Legend::setColor( uint dataset, const QColor& color )
00609 {
00610 if( d->brushes[ dataset ] == color ) return;
00611 d->brushes[ dataset ] = color;
00612 setNeedRebuild();
00613 update();
00614 }
00615
00616 void Legend::setBrush( uint dataset, const QBrush& brush )
00617 {
00618 if( d->brushes[ dataset ] == brush ) return;
00619 d->brushes[ dataset ] = brush;
00620 setNeedRebuild();
00621 update();
00622 }
00623
00624 QBrush Legend::brush( uint dataset ) const
00625 {
00626 if( d->brushes.find( dataset ) != d->brushes.end() )
00627 return d->brushes[ dataset ];
00628 else
00629 return d->modelBrushes[ dataset ];
00630 }
00631
00632 const QMap<uint,QBrush> Legend::brushes() const
00633 {
00634 return d->brushes;
00635 }
00636
00637
00638 void Legend::setBrushesFromDiagram( KDChart::AbstractDiagram* diagram )
00639 {
00640 bool bChangesDone = false;
00641 QList<QBrush> datasetBrushes = diagram->datasetBrushes();
00642 for( int i = 0; i < datasetBrushes.count(); i++ ){
00643 if( d->brushes[ i ] != datasetBrushes[ i ] ){
00644 d->brushes[ i ] = datasetBrushes[ i ];
00645 bChangesDone = true;
00646 }
00647 }
00648 if( bChangesDone ) {
00649 setNeedRebuild();
00650 update();
00651 }
00652 }
00653
00654
00655 void Legend::setPen( uint dataset, const QPen& pen )
00656 {
00657 if( d->pens[dataset] == pen ) return;
00658 d->pens[dataset] = pen;
00659 setNeedRebuild();
00660 update();
00661 }
00662
00663 QPen Legend::pen( uint dataset ) const
00664 {
00665 if( d->pens.find( dataset ) != d->pens.end() )
00666 return d->pens[dataset];
00667 else
00668 return d->modelPens[ dataset ];
00669 }
00670
00671 const QMap<uint,QPen> Legend::pens() const
00672 {
00673 return d->pens;
00674 }
00675
00676
00677 void Legend::setMarkerAttributes( uint dataset, const MarkerAttributes& markerAttributes )
00678 {
00679 if( d->markerAttributes[dataset] == markerAttributes ) return;
00680 d->markerAttributes[ dataset ] = markerAttributes;
00681 setNeedRebuild();
00682 update();
00683 }
00684
00685 MarkerAttributes Legend::markerAttributes( uint dataset ) const
00686 {
00687 if( d->markerAttributes.find( dataset ) != d->markerAttributes.end() )
00688 return d->markerAttributes[ dataset ];
00689 else if ( static_cast<uint>( d->modelMarkers.count() ) > dataset )
00690 return d->modelMarkers[ dataset ];
00691 return MarkerAttributes();
00692 }
00693
00694 const QMap<uint, MarkerAttributes> Legend::markerAttributes() const
00695 {
00696 return d->markerAttributes;
00697 }
00698
00699
00700 void Legend::setTextAttributes( const TextAttributes &a )
00701 {
00702 if( d->textAttributes == a ) return;
00703 d->textAttributes = a;
00704 setNeedRebuild();
00705 }
00706
00707 TextAttributes Legend::textAttributes() const
00708 {
00709 return d->textAttributes;
00710 }
00711
00712 void Legend::setTitleText( const QString& text )
00713 {
00714 if( d->titleText == text ) return;
00715 d->titleText = text;
00716 setNeedRebuild();
00717 }
00718
00719 QString Legend::titleText() const
00720 {
00721 return d->titleText;
00722 }
00723
00724 void Legend::setTitleTextAttributes( const TextAttributes &a )
00725 {
00726 if( d->titleTextAttributes == a ) return;
00727 d->titleTextAttributes = a;
00728 setNeedRebuild();
00729 }
00730
00731 TextAttributes Legend::titleTextAttributes() const
00732 {
00733 return d->titleTextAttributes;
00734 }
00735
00736 void Legend::forceRebuild()
00737 {
00738 #ifdef DEBUG_LEGEND_PAINT
00739 qDebug() << "entering Legend::forceRebuild()";
00740 #endif
00741
00742 buildLegend();
00743 #ifdef DEBUG_LEGEND_PAINT
00744 qDebug() << "leaving Legend::forceRebuild()";
00745 #endif
00746 }
00747
00748 void Legend::setSpacing( uint space )
00749 {
00750 if( d->spacing == space && d->layout->spacing() == static_cast<int>(space) ) return;
00751 d->spacing = space;
00752 d->layout->setSpacing( space );
00753 setNeedRebuild();
00754 }
00755
00756 uint Legend::spacing() const
00757 {
00758 return d->spacing;
00759 }
00760
00761 void Legend::setDefaultColors()
00762 {
00763 setColor( 0, Qt::red );
00764 setColor( 1, Qt::green );
00765 setColor( 2, Qt::blue );
00766 setColor( 3, Qt::cyan );
00767 setColor( 4, Qt::magenta );
00768 setColor( 5, Qt::yellow );
00769 setColor( 6, Qt::darkRed );
00770 setColor( 7, Qt::darkGreen );
00771 setColor( 8, Qt::darkBlue );
00772 setColor( 9, Qt::darkCyan );
00773 setColor( 10, Qt::darkMagenta );
00774 setColor( 11, Qt::darkYellow );
00775 }
00776
00777 void Legend::setRainbowColors()
00778 {
00779 setColor( 0, QColor(255, 0,196) );
00780 setColor( 1, QColor(255, 0, 96) );
00781 setColor( 2, QColor(255, 128,64) );
00782 setColor( 3, Qt::yellow );
00783 setColor( 4, Qt::green );
00784 setColor( 5, Qt::cyan );
00785 setColor( 6, QColor( 96, 96,255) );
00786 setColor( 7, QColor(160, 0,255) );
00787 for( int i = 8; i < 16; ++i )
00788 setColor( i, brush( i - 8 ).color().light() );
00789 }
00790
00791 void Legend::setSubduedColors( bool ordered )
00792 {
00793 static const int NUM_SUBDUEDCOLORS = 18;
00794 static const QColor SUBDUEDCOLORS[ NUM_SUBDUEDCOLORS ] = {
00795 QColor( 0xe0,0x7f,0x70 ),
00796 QColor( 0xe2,0xa5,0x6f ),
00797 QColor( 0xe0,0xc9,0x70 ),
00798 QColor( 0xd1,0xe0,0x70 ),
00799 QColor( 0xac,0xe0,0x70 ),
00800 QColor( 0x86,0xe0,0x70 ),
00801 QColor( 0x70,0xe0,0x7f ),
00802 QColor( 0x70,0xe0,0xa4 ),
00803 QColor( 0x70,0xe0,0xc9 ),
00804 QColor( 0x70,0xd1,0xe0 ),
00805 QColor( 0x70,0xac,0xe0 ),
00806 QColor( 0x70,0x86,0xe0 ),
00807 QColor( 0x7f,0x70,0xe0 ),
00808 QColor( 0xa4,0x70,0xe0 ),
00809 QColor( 0xc9,0x70,0xe0 ),
00810 QColor( 0xe0,0x70,0xd1 ),
00811 QColor( 0xe0,0x70,0xac ),
00812 QColor( 0xe0,0x70,0x86 ),
00813 };
00814 if( ordered )
00815 for(int i=0; i<NUM_SUBDUEDCOLORS; ++i)
00816 setColor( i, SUBDUEDCOLORS[i] );
00817 else{
00818 setColor( 0, SUBDUEDCOLORS[ 0] );
00819 setColor( 1, SUBDUEDCOLORS[ 5] );
00820 setColor( 2, SUBDUEDCOLORS[10] );
00821 setColor( 3, SUBDUEDCOLORS[15] );
00822 setColor( 4, SUBDUEDCOLORS[ 2] );
00823 setColor( 5, SUBDUEDCOLORS[ 7] );
00824 setColor( 6, SUBDUEDCOLORS[12] );
00825 setColor( 7, SUBDUEDCOLORS[17] );
00826 setColor( 8, SUBDUEDCOLORS[ 4] );
00827 setColor( 9, SUBDUEDCOLORS[ 9] );
00828 setColor(10, SUBDUEDCOLORS[14] );
00829 setColor(11, SUBDUEDCOLORS[ 1] );
00830 setColor(12, SUBDUEDCOLORS[ 6] );
00831 setColor(13, SUBDUEDCOLORS[11] );
00832 setColor(14, SUBDUEDCOLORS[16] );
00833 setColor(15, SUBDUEDCOLORS[ 3] );
00834 setColor(16, SUBDUEDCOLORS[ 8] );
00835 setColor(17, SUBDUEDCOLORS[13] );
00836 }
00837 }
00838
00839 void Legend::resizeEvent ( QResizeEvent * event )
00840 {
00841 Q_UNUSED( event );
00842 #ifdef DEBUG_LEGEND_PAINT
00843 qDebug() << "Legend::resizeEvent() called";
00844 #endif
00845 forceRebuild();
00846 sizeHint();
00847 QTimer::singleShot(0, this, SLOT(emitPositionChanged()));
00848 }
00849
00850 void Legend::buildLegend()
00851 {
00852
00853
00854
00855
00856
00857
00858
00859
00860
00861
00862
00863
00864
00865
00866
00867
00868 Q_FOREACH( QLayoutItem* layoutItem, d->layoutItems ) {
00869 d->layout->removeItem( layoutItem );
00870 }
00871 qDeleteAll( d->layoutItems );
00872 d->layoutItems.clear();
00873
00874 if( orientation() == Qt::Vertical ) {
00875 d->layout->setColumnStretch( 6, 1 );
00876 } else {
00877 d->layout->setColumnStretch( 6, 0 );
00878 }
00879
00880 d->modelLabels.clear();
00881 d->modelBrushes.clear();
00882 d->modelPens.clear();
00883 d->modelMarkers.clear();
00884
00885 for (int i = 0; i < d->observers.size(); ++i){
00886 const AbstractDiagram* diagram = d->observers.at(i)->diagram();
00887 if( diagram ){
00888
00889 const QStringList diagramLabels( diagram->datasetLabels() );
00890 const QList<QBrush> diagramBrushes( diagram->datasetBrushes() );
00891 const QList<QPen> diagramPens( diagram->datasetPens() );
00892 const QList<MarkerAttributes> diagramMarkers( diagram->datasetMarkers() );
00893 const int begin = sortOrder() == Qt::AscendingOrder ? 0 : diagramLabels.count() - 1;
00894 const int end = sortOrder() == Qt::AscendingOrder ? diagramLabels.count() : -1;
00895 for ( int dataset = begin; dataset != end; dataset += begin < end ? 1 : -1 )
00896 {
00897
00898
00899 if( !diagram->isHidden( dataset ) && !datasetIsHidden( dataset ) ){
00900 d->modelLabels += diagramLabels[ dataset ];
00901 d->modelBrushes += diagramBrushes[ dataset ];
00902 d->modelPens += diagramPens[ dataset ];
00903 d->modelMarkers += diagramMarkers[ dataset ];
00904 }
00905 }
00906 }
00907 }
00908
00909 Q_ASSERT( d->modelLabels.count() == d->modelBrushes.count() );
00910
00911
00912 if( !titleText().isEmpty() && titleTextAttributes().isVisible() ) {
00913
00914 KDChart::TextLayoutItem* titleItem =
00915 new KDChart::TextLayoutItem( titleText(),
00916 titleTextAttributes(),
00917 referenceArea(),
00918 (orientation() == Qt::Vertical)
00919 ? KDChartEnums::MeasureOrientationMinimum
00920 : KDChartEnums::MeasureOrientationHorizontal,
00921 d->textAlignment );
00922 titleItem->setParentWidget( this );
00923
00924 d->layoutItems << titleItem;
00925 if( orientation() == Qt::Vertical )
00926 d->layout->addItem( titleItem, 0, 0, 1, 5, Qt::AlignCenter );
00927 else
00928 d->layout->addItem( titleItem, 0, 0, 1, d->modelLabels.count() ? (d->modelLabels.count()*4) : 1, Qt::AlignCenter );
00929
00930
00931 if( showLines() && d->modelLabels.count() ) {
00932 KDChart::HorizontalLineLayoutItem* lineItem = new KDChart::HorizontalLineLayoutItem();
00933 d->layoutItems << lineItem;
00934 if( orientation() == Qt::Vertical ){
00935 d->layout->addItem( lineItem, 1, 0, 1, 5, Qt::AlignCenter );
00936 }else{
00937
00938 d->layout->addItem( lineItem, 1, 0, 1, 1+d->modelLabels.count()*4, Qt::AlignCenter );
00939 }
00940 }
00941 }
00942
00943 const KDChartEnums::MeasureOrientation orient =
00944 (orientation() == Qt::Vertical)
00945 ? KDChartEnums::MeasureOrientationMinimum
00946 : KDChartEnums::MeasureOrientationHorizontal;
00947 const TextAttributes labelAttrs( textAttributes() );
00948 const qreal fontHeight = labelAttrs.calculatedFontSize( referenceArea(), orient );
00949 const LegendStyle style = legendStyle();
00950
00951
00952 const bool bShowMarkers = (style != LinesOnly);
00953
00954 QSizeF maxMarkersSize(1.0, 1.0);
00955 QVector <MarkerAttributes> markerAttrs( d->modelLabels.count() );
00956 if( bShowMarkers ){
00957 for ( int dataset = 0; dataset < d->modelLabels.count(); ++dataset ) {
00958 markerAttrs[dataset] = markerAttributes( dataset );
00959 QSizeF siz;
00960 if( useAutomaticMarkerSize() ||
00961 ! markerAttrs[dataset].markerSize().isValid() )
00962 {
00963 siz = QSizeF(fontHeight, fontHeight);
00964 markerAttrs[dataset].setMarkerSize( siz );
00965 }else{
00966 siz = markerAttrs[dataset].markerSize();
00967 }
00968 maxMarkersSize =
00969 QSizeF(qMax(maxMarkersSize.width(), siz.width()),
00970 qMax(maxMarkersSize.height(), siz.height()));
00971 }
00972 }
00973
00974
00975
00976
00977
00978
00979 const int markerOffsOnLine = 8;
00980
00981 int maxLineLength = 18;
00982 {
00983 bool hasComplexPenStyle = false;
00984 for ( int dataset = 0; dataset < d->modelLabels.count(); ++dataset ){
00985 const QPen pn = pen(dataset);
00986 const Qt::PenStyle ps = pn.style();
00987 if( ps != Qt::NoPen ){
00988 maxLineLength = qMax( pn.width() * 18, maxLineLength );
00989 if( ps != Qt::SolidLine )
00990 hasComplexPenStyle = true;
00991 }
00992 }
00993 if( hasComplexPenStyle && bShowMarkers )
00994 maxLineLength =
00995 maxLineLength + markerOffsOnLine +
00996 static_cast<int>(maxMarkersSize.width());
00997 }
00998
00999 #define ADD_MARKER_SPACER_FOR_HORIZONTAL_MODE( column ) \
01000 { \
01001 if( orientation() != Qt::Vertical ) \
01002 d->layout->addItem( new QSpacerItem( spacing(), 1 ), \
01003 2, \
01004 column ); \
01005 }
01006
01007
01008 ADD_MARKER_SPACER_FOR_HORIZONTAL_MODE( 0 )
01009
01010
01011 for ( int dataset = 0; dataset < d->modelLabels.count(); ++dataset ) {
01012 KDChart::AbstractLayoutItem* markerLineItem = 0;
01013
01014
01015
01016 const QBrush markerBrush = markerAttrs[dataset].markerColor().isValid() ?
01017 QBrush(markerAttrs[dataset].markerColor()) : brush( dataset );
01018 switch( style ){
01019 case( MarkersOnly ):
01020 markerLineItem = new KDChart::MarkerLayoutItem(
01021 diagram(),
01022 markerAttrs[dataset],
01023 markerBrush,
01024 markerAttrs[dataset].pen(),
01025 Qt::AlignLeft );
01026 break;
01027 case( LinesOnly ):
01028 markerLineItem = new KDChart::LineLayoutItem(
01029 diagram(),
01030 maxLineLength,
01031 pen( dataset ),
01032 Qt::AlignCenter );
01033 break;
01034 case( MarkersAndLines ):
01035 markerLineItem = new KDChart::LineWithMarkerLayoutItem(
01036 diagram(),
01037 maxLineLength,
01038 pen( dataset ),
01039 markerOffsOnLine,
01040 markerAttrs[dataset],
01041 markerBrush,
01042 markerAttrs[dataset].pen(),
01043 Qt::AlignCenter );
01044 break;
01045 default:
01046 Q_ASSERT( false );
01047 }
01048 if( markerLineItem ){
01049 d->layoutItems << markerLineItem;
01050 if( orientation() == Qt::Vertical )
01051 d->layout->addItem( markerLineItem,
01052 dataset*2+2,
01053 1,
01054 1, 1, Qt::AlignCenter );
01055 else
01056 d->layout->addItem( markerLineItem,
01057 2,
01058 dataset*4+1 );
01059 }
01060
01061
01062 KDChart::TextLayoutItem* labelItem =
01063 new KDChart::TextLayoutItem( text( dataset ),
01064 labelAttrs,
01065 referenceArea(), orient,
01066 d->textAlignment );
01067 labelItem->setParentWidget( this );
01068
01069 d->layoutItems << labelItem;
01070 if( orientation() == Qt::Vertical )
01071 d->layout->addItem( labelItem,
01072 dataset*2+2,
01073 3 );
01074 else
01075 d->layout->addItem( labelItem,
01076 2,
01077 dataset*4+2 );
01078
01079
01080 if( orientation() == Qt::Vertical && showLines() && dataset != d->modelLabels.count()-1 ) {
01081 KDChart::HorizontalLineLayoutItem* lineItem = new KDChart::HorizontalLineLayoutItem();
01082 d->layoutItems << lineItem;
01083 d->layout->addItem( lineItem,
01084 dataset*2+1+2,
01085 0,
01086 1, 5, Qt::AlignCenter );
01087 }
01088
01089
01090 if( orientation() == Qt::Horizontal && showLines() && dataset != d->modelLabels.count()-1 ) {
01091 KDChart::VerticalLineLayoutItem* lineItem = new KDChart::VerticalLineLayoutItem();
01092 d->layoutItems << lineItem;
01093 d->layout->addItem( lineItem,
01094 2,
01095 style == MarkersAndLines ? dataset*4+4 : dataset*4+3 ,
01096 1, 1, Qt::AlignCenter );
01097 }
01098
01099
01100 ADD_MARKER_SPACER_FOR_HORIZONTAL_MODE( dataset*4+4 )
01101 }
01102
01103
01104 if( orientation() == Qt::Vertical && showLines() && d->modelLabels.count() ) {
01105 KDChart::VerticalLineLayoutItem* lineItem = new KDChart::VerticalLineLayoutItem();
01106 d->layoutItems << lineItem;
01107 d->layout->addItem( lineItem, 2, 2, d->modelLabels.count()*2, 1 );
01108 }
01109
01110
01111 activateTheLayout();
01112
01113 emit propertiesChanged();
01114
01115
01116 #ifdef DEBUG_LEGEND_PAINT
01117 qDebug() << "leaving Legend::buildLegend()";
01118 #endif
01119 }
01120
01121 void Legend::setHiddenDatasets( const QList<uint> hiddenDatasets )
01122 {
01123 d->hiddenDatasets = hiddenDatasets;
01124 }
01125
01126 const QList<uint> Legend::hiddenDatasets() const
01127 {
01128 return d->hiddenDatasets;
01129 }
01130
01131 void Legend::setDatasetHidden( uint dataset, bool hidden )
01132 {
01133 if( hidden && !d->hiddenDatasets.contains( dataset ) )
01134 d->hiddenDatasets.append( dataset );
01135 else if( !hidden && d->hiddenDatasets.contains( dataset ) )
01136 d->hiddenDatasets.removeAll( dataset );
01137 }
01138
01139 bool Legend::datasetIsHidden( uint dataset ) const
01140 {
01141 return d->hiddenDatasets.contains( dataset );
01142 }
01143