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
00400
00401 QList<AbstractDiagram*> diagrams;
00402 for (int i = 0; i < d->observers.size(); ++i)
00403 diagrams.append( d->observers.at(i)->diagram() );
00404 for (int i = 0; i < diagrams.count(); ++i)
00405 removeDiagram( diagrams[i] );
00406 }
00407
00408 void Legend::replaceDiagram( AbstractDiagram* newDiagram,
00409 AbstractDiagram* oldDiagram )
00410 {
00411 KDChart::AbstractDiagram* old = oldDiagram;
00412 if( ! d->observers.isEmpty() && ! old ){
00413 old = d->observers.first()->diagram();
00414 if( ! old )
00415 d->observers.removeFirst();
00416 }
00417 if( old )
00418 removeDiagram( old );
00419 if( newDiagram )
00420 addDiagram( newDiagram );
00421 }
00422
00423 uint Legend::dataSetOffset(KDChart::AbstractDiagram* diagram)
00424 {
00425 uint offset = 0;
00426
00427 for (int i = 0; i < d->observers.count(); ++i)
00428 {
00429 if(d->observers.at(i)->diagram() == diagram)
00430 return offset;
00431
00432 KDChart::AbstractDiagram* diagram = d->observers.at(i)->diagram();
00433 if(!diagram->model())
00434 continue;
00435
00436 offset = offset + diagram->model()->columnCount();
00437 }
00438
00439 return offset;
00440 }
00441
00442 void Legend::setDiagram( KDChart::AbstractDiagram* newDiagram )
00443 {
00444 replaceDiagram( newDiagram );
00445 }
00446
00447 void Legend::resetDiagram( AbstractDiagram* oldDiagram )
00448 {
00449
00450 removeDiagram( oldDiagram );
00451 }
00452
00453 void Legend::setVisible( bool visible )
00454 {
00455 if( isVisible() == visible )
00456 return;
00457 QWidget::setVisible( visible );
00458 emitPositionChanged();
00459 }
00460
00461 void Legend::setNeedRebuild()
00462 {
00463
00464 buildLegend();
00465 sizeHint();
00466 }
00467
00468 void Legend::setPosition( Position position )
00469 {
00470 if( d->position == position )
00471 return;
00472 d->position = position;
00473 emitPositionChanged();
00474 }
00475
00476 void Legend::emitPositionChanged()
00477 {
00478 emit positionChanged( this );
00479 emit propertiesChanged();
00480 }
00481
00482
00483 Position Legend::position() const
00484 {
00485 return d->position;
00486 }
00487
00488 void Legend::setAlignment( Qt::Alignment alignment )
00489 {
00490 if( d->alignment == alignment )
00491 return;
00492 d->alignment = alignment;
00493 emitPositionChanged();
00494 }
00495
00496 Qt::Alignment Legend::alignment() const
00497 {
00498 return d->alignment;
00499 }
00500
00501 void Legend::setTextAlignment( Qt::Alignment alignment )
00502 {
00503 if( d->textAlignment == alignment )
00504 return;
00505 d->textAlignment = alignment;
00506 emitPositionChanged();
00507 }
00508
00509 Qt::Alignment Legend::textAlignment() const
00510 {
00511 return d->textAlignment;
00512 }
00513
00514 void Legend::setFloatingPosition( const RelativePosition& relativePosition )
00515 {
00516 d->position = Position::Floating;
00517 if( d->relativePosition != relativePosition ){
00518 d->relativePosition = relativePosition;
00519 emitPositionChanged();
00520 }
00521 }
00522
00523 const RelativePosition Legend::floatingPosition() const
00524 {
00525 return d->relativePosition;
00526 }
00527
00528 void Legend::setOrientation( Qt::Orientation orientation )
00529 {
00530 if( d->orientation == orientation ) return;
00531 d->orientation = orientation;
00532 setNeedRebuild();
00533 emitPositionChanged();
00534 }
00535
00536 Qt::Orientation Legend::orientation() const
00537 {
00538 return d->orientation;
00539 }
00540
00541 void Legend::setSortOrder( Qt::SortOrder order )
00542 {
00543 if( d->order == order )
00544 return;
00545 d->order = order;
00546 setNeedRebuild();
00547 emitPositionChanged();
00548 }
00549
00550 Qt::SortOrder Legend::sortOrder() const
00551 {
00552 return d->order;
00553 }
00554
00555 void Legend::setShowLines( bool legendShowLines )
00556 {
00557 if( d->showLines == legendShowLines ) return;
00558 d->showLines = legendShowLines;
00559 setNeedRebuild();
00560 emitPositionChanged();
00561 }
00562
00563 bool Legend::showLines() const
00564 {
00565 return d->showLines;
00566 }
00567
00568 void Legend::setUseAutomaticMarkerSize( bool useAutomaticMarkerSize )
00569 {
00570 d->useAutomaticMarkerSize = useAutomaticMarkerSize;
00571 setNeedRebuild();
00572 emitPositionChanged();
00573 }
00574
00575 bool Legend::useAutomaticMarkerSize() const
00576 {
00577 return d->useAutomaticMarkerSize;
00578 }
00579
00585 void Legend::resetTexts()
00586 {
00587 if( ! d->texts.count() ) return;
00588 d->texts.clear();
00589 setNeedRebuild();
00590 }
00591
00592 void Legend::setText( uint dataset, const QString& text )
00593 {
00594 if( d->texts[ dataset ] == text ) return;
00595 d->texts[ dataset ] = text;
00596 setNeedRebuild();
00597 }
00598
00599 QString Legend::text( uint dataset ) const
00600 {
00601 if( d->texts.find( dataset ) != d->texts.end() ){
00602 return d->texts[ dataset ];
00603 }else{
00604 return d->modelLabels[ dataset ];
00605 }
00606 }
00607
00608 const QMap<uint,QString> Legend::texts() const
00609 {
00610 return d->texts;
00611 }
00612
00613 void Legend::setColor( uint dataset, const QColor& color )
00614 {
00615 if( d->brushes[ dataset ] == color ) return;
00616 d->brushes[ dataset ] = color;
00617 setNeedRebuild();
00618 update();
00619 }
00620
00621 void Legend::setBrush( uint dataset, const QBrush& brush )
00622 {
00623 if( d->brushes[ dataset ] == brush ) return;
00624 d->brushes[ dataset ] = brush;
00625 setNeedRebuild();
00626 update();
00627 }
00628
00629 QBrush Legend::brush( uint dataset ) const
00630 {
00631 if( d->brushes.find( dataset ) != d->brushes.end() )
00632 return d->brushes[ dataset ];
00633 else
00634 return d->modelBrushes[ dataset ];
00635 }
00636
00637 const QMap<uint,QBrush> Legend::brushes() const
00638 {
00639 return d->brushes;
00640 }
00641
00642
00643 void Legend::setBrushesFromDiagram( KDChart::AbstractDiagram* diagram )
00644 {
00645 bool bChangesDone = false;
00646 QList<QBrush> datasetBrushes = diagram->datasetBrushes();
00647 for( int i = 0; i < datasetBrushes.count(); i++ ){
00648 if( d->brushes[ i ] != datasetBrushes[ i ] ){
00649 d->brushes[ i ] = datasetBrushes[ i ];
00650 bChangesDone = true;
00651 }
00652 }
00653 if( bChangesDone ) {
00654 setNeedRebuild();
00655 update();
00656 }
00657 }
00658
00659
00660 void Legend::setPen( uint dataset, const QPen& pen )
00661 {
00662 if( d->pens[dataset] == pen ) return;
00663 d->pens[dataset] = pen;
00664 setNeedRebuild();
00665 update();
00666 }
00667
00668 QPen Legend::pen( uint dataset ) const
00669 {
00670 if( d->pens.find( dataset ) != d->pens.end() )
00671 return d->pens[dataset];
00672 else
00673 return d->modelPens[ dataset ];
00674 }
00675
00676 const QMap<uint,QPen> Legend::pens() const
00677 {
00678 return d->pens;
00679 }
00680
00681
00682 void Legend::setMarkerAttributes( uint dataset, const MarkerAttributes& markerAttributes )
00683 {
00684 if( d->markerAttributes[dataset] == markerAttributes ) return;
00685 d->markerAttributes[ dataset ] = markerAttributes;
00686 setNeedRebuild();
00687 update();
00688 }
00689
00690 MarkerAttributes Legend::markerAttributes( uint dataset ) const
00691 {
00692 if( d->markerAttributes.find( dataset ) != d->markerAttributes.end() )
00693 return d->markerAttributes[ dataset ];
00694 else if ( static_cast<uint>( d->modelMarkers.count() ) > dataset )
00695 return d->modelMarkers[ dataset ];
00696 return MarkerAttributes();
00697 }
00698
00699 const QMap<uint, MarkerAttributes> Legend::markerAttributes() const
00700 {
00701 return d->markerAttributes;
00702 }
00703
00704
00705 void Legend::setTextAttributes( const TextAttributes &a )
00706 {
00707 if( d->textAttributes == a ) return;
00708 d->textAttributes = a;
00709 setNeedRebuild();
00710 }
00711
00712 TextAttributes Legend::textAttributes() const
00713 {
00714 return d->textAttributes;
00715 }
00716
00717 void Legend::setTitleText( const QString& text )
00718 {
00719 if( d->titleText == text ) return;
00720 d->titleText = text;
00721 setNeedRebuild();
00722 }
00723
00724 QString Legend::titleText() const
00725 {
00726 return d->titleText;
00727 }
00728
00729 void Legend::setTitleTextAttributes( const TextAttributes &a )
00730 {
00731 if( d->titleTextAttributes == a ) return;
00732 d->titleTextAttributes = a;
00733 setNeedRebuild();
00734 }
00735
00736 TextAttributes Legend::titleTextAttributes() const
00737 {
00738 return d->titleTextAttributes;
00739 }
00740
00741 void Legend::forceRebuild()
00742 {
00743 #ifdef DEBUG_LEGEND_PAINT
00744 qDebug() << "entering Legend::forceRebuild()";
00745 #endif
00746
00747 buildLegend();
00748 #ifdef DEBUG_LEGEND_PAINT
00749 qDebug() << "leaving Legend::forceRebuild()";
00750 #endif
00751 }
00752
00753 void Legend::setSpacing( uint space )
00754 {
00755 if( d->spacing == space && d->layout->spacing() == static_cast<int>(space) ) return;
00756 d->spacing = space;
00757 d->layout->setSpacing( space );
00758 setNeedRebuild();
00759 }
00760
00761 uint Legend::spacing() const
00762 {
00763 return d->spacing;
00764 }
00765
00766 void Legend::setDefaultColors()
00767 {
00768 setColor( 0, Qt::red );
00769 setColor( 1, Qt::green );
00770 setColor( 2, Qt::blue );
00771 setColor( 3, Qt::cyan );
00772 setColor( 4, Qt::magenta );
00773 setColor( 5, Qt::yellow );
00774 setColor( 6, Qt::darkRed );
00775 setColor( 7, Qt::darkGreen );
00776 setColor( 8, Qt::darkBlue );
00777 setColor( 9, Qt::darkCyan );
00778 setColor( 10, Qt::darkMagenta );
00779 setColor( 11, Qt::darkYellow );
00780 }
00781
00782 void Legend::setRainbowColors()
00783 {
00784 setColor( 0, QColor(255, 0,196) );
00785 setColor( 1, QColor(255, 0, 96) );
00786 setColor( 2, QColor(255, 128,64) );
00787 setColor( 3, Qt::yellow );
00788 setColor( 4, Qt::green );
00789 setColor( 5, Qt::cyan );
00790 setColor( 6, QColor( 96, 96,255) );
00791 setColor( 7, QColor(160, 0,255) );
00792 for( int i = 8; i < 16; ++i )
00793 setColor( i, brush( i - 8 ).color().light() );
00794 }
00795
00796 void Legend::setSubduedColors( bool ordered )
00797 {
00798 static const int NUM_SUBDUEDCOLORS = 18;
00799 static const QColor SUBDUEDCOLORS[ NUM_SUBDUEDCOLORS ] = {
00800 QColor( 0xe0,0x7f,0x70 ),
00801 QColor( 0xe2,0xa5,0x6f ),
00802 QColor( 0xe0,0xc9,0x70 ),
00803 QColor( 0xd1,0xe0,0x70 ),
00804 QColor( 0xac,0xe0,0x70 ),
00805 QColor( 0x86,0xe0,0x70 ),
00806 QColor( 0x70,0xe0,0x7f ),
00807 QColor( 0x70,0xe0,0xa4 ),
00808 QColor( 0x70,0xe0,0xc9 ),
00809 QColor( 0x70,0xd1,0xe0 ),
00810 QColor( 0x70,0xac,0xe0 ),
00811 QColor( 0x70,0x86,0xe0 ),
00812 QColor( 0x7f,0x70,0xe0 ),
00813 QColor( 0xa4,0x70,0xe0 ),
00814 QColor( 0xc9,0x70,0xe0 ),
00815 QColor( 0xe0,0x70,0xd1 ),
00816 QColor( 0xe0,0x70,0xac ),
00817 QColor( 0xe0,0x70,0x86 ),
00818 };
00819 if( ordered )
00820 for(int i=0; i<NUM_SUBDUEDCOLORS; ++i)
00821 setColor( i, SUBDUEDCOLORS[i] );
00822 else{
00823 setColor( 0, SUBDUEDCOLORS[ 0] );
00824 setColor( 1, SUBDUEDCOLORS[ 5] );
00825 setColor( 2, SUBDUEDCOLORS[10] );
00826 setColor( 3, SUBDUEDCOLORS[15] );
00827 setColor( 4, SUBDUEDCOLORS[ 2] );
00828 setColor( 5, SUBDUEDCOLORS[ 7] );
00829 setColor( 6, SUBDUEDCOLORS[12] );
00830 setColor( 7, SUBDUEDCOLORS[17] );
00831 setColor( 8, SUBDUEDCOLORS[ 4] );
00832 setColor( 9, SUBDUEDCOLORS[ 9] );
00833 setColor(10, SUBDUEDCOLORS[14] );
00834 setColor(11, SUBDUEDCOLORS[ 1] );
00835 setColor(12, SUBDUEDCOLORS[ 6] );
00836 setColor(13, SUBDUEDCOLORS[11] );
00837 setColor(14, SUBDUEDCOLORS[16] );
00838 setColor(15, SUBDUEDCOLORS[ 3] );
00839 setColor(16, SUBDUEDCOLORS[ 8] );
00840 setColor(17, SUBDUEDCOLORS[13] );
00841 }
00842 }
00843
00844 void Legend::resizeEvent ( QResizeEvent * event )
00845 {
00846 Q_UNUSED( event );
00847 #ifdef DEBUG_LEGEND_PAINT
00848 qDebug() << "Legend::resizeEvent() called";
00849 #endif
00850 forceRebuild();
00851 sizeHint();
00852 QTimer::singleShot(0, this, SLOT(emitPositionChanged()));
00853 }
00854
00855 void Legend::buildLegend()
00856 {
00857
00858
00859
00860
00861
00862
00863
00864
00865
00866
00867
00868
00869
00870
00871
00872
00873 Q_FOREACH( QLayoutItem* layoutItem, d->layoutItems ) {
00874 d->layout->removeItem( layoutItem );
00875 }
00876 qDeleteAll( d->layoutItems );
00877 d->layoutItems.clear();
00878
00879 if( orientation() == Qt::Vertical ) {
00880 d->layout->setColumnStretch( 6, 1 );
00881 } else {
00882 d->layout->setColumnStretch( 6, 0 );
00883 }
00884
00885 d->modelLabels.clear();
00886 d->modelBrushes.clear();
00887 d->modelPens.clear();
00888 d->modelMarkers.clear();
00889
00890 for (int i = 0; i < d->observers.size(); ++i){
00891 const AbstractDiagram* diagram = d->observers.at(i)->diagram();
00892 if( diagram ){
00893
00894 const QStringList diagramLabels( diagram->datasetLabels() );
00895 const QList<QBrush> diagramBrushes( diagram->datasetBrushes() );
00896 const QList<QPen> diagramPens( diagram->datasetPens() );
00897 const QList<MarkerAttributes> diagramMarkers( diagram->datasetMarkers() );
00898 const int begin = sortOrder() == Qt::AscendingOrder ? 0 : diagramLabels.count() - 1;
00899 const int end = sortOrder() == Qt::AscendingOrder ? diagramLabels.count() : -1;
00900 for ( int dataset = begin; dataset != end; dataset += begin < end ? 1 : -1 )
00901 {
00902
00903
00904 if( !diagram->isHidden( dataset ) && !datasetIsHidden( dataset ) ){
00905 d->modelLabels += diagramLabels[ dataset ];
00906 d->modelBrushes += diagramBrushes[ dataset ];
00907 d->modelPens += diagramPens[ dataset ];
00908 d->modelMarkers += diagramMarkers[ dataset ];
00909 }
00910 }
00911 }
00912 }
00913
00914 Q_ASSERT( d->modelLabels.count() == d->modelBrushes.count() );
00915
00916
00917 if( !titleText().isEmpty() && titleTextAttributes().isVisible() ) {
00918
00919 KDChart::TextLayoutItem* titleItem =
00920 new KDChart::TextLayoutItem( titleText(),
00921 titleTextAttributes(),
00922 referenceArea(),
00923 (orientation() == Qt::Vertical)
00924 ? KDChartEnums::MeasureOrientationMinimum
00925 : KDChartEnums::MeasureOrientationHorizontal,
00926 d->textAlignment );
00927 titleItem->setParentWidget( this );
00928
00929 d->layoutItems << titleItem;
00930 if( orientation() == Qt::Vertical )
00931 d->layout->addItem( titleItem, 0, 0, 1, 5, Qt::AlignCenter );
00932 else
00933 d->layout->addItem( titleItem, 0, 0, 1, d->modelLabels.count() ? (d->modelLabels.count()*4) : 1, Qt::AlignCenter );
00934
00935
00936 if( showLines() && d->modelLabels.count() ) {
00937 KDChart::HorizontalLineLayoutItem* lineItem = new KDChart::HorizontalLineLayoutItem();
00938 d->layoutItems << lineItem;
00939 if( orientation() == Qt::Vertical ){
00940 d->layout->addItem( lineItem, 1, 0, 1, 5, Qt::AlignCenter );
00941 }else{
00942
00943 d->layout->addItem( lineItem, 1, 0, 1, 1+d->modelLabels.count()*4, Qt::AlignCenter );
00944 }
00945 }
00946 }
00947
00948 const KDChartEnums::MeasureOrientation orient =
00949 (orientation() == Qt::Vertical)
00950 ? KDChartEnums::MeasureOrientationMinimum
00951 : KDChartEnums::MeasureOrientationHorizontal;
00952 const TextAttributes labelAttrs( textAttributes() );
00953 const qreal fontHeight = labelAttrs.calculatedFontSize( referenceArea(), orient );
00954 const LegendStyle style = legendStyle();
00955
00956
00957 const bool bShowMarkers = (style != LinesOnly);
00958
00959 QSizeF maxMarkersSize(1.0, 1.0);
00960 QVector <MarkerAttributes> markerAttrs( d->modelLabels.count() );
00961 if( bShowMarkers ){
00962 for ( int dataset = 0; dataset < d->modelLabels.count(); ++dataset ) {
00963 markerAttrs[dataset] = markerAttributes( dataset );
00964 QSizeF siz;
00965 if( useAutomaticMarkerSize() ||
00966 ! markerAttrs[dataset].markerSize().isValid() )
00967 {
00968 siz = QSizeF(fontHeight, fontHeight);
00969 markerAttrs[dataset].setMarkerSize( siz );
00970 }else{
00971 siz = markerAttrs[dataset].markerSize();
00972 }
00973 maxMarkersSize =
00974 QSizeF(qMax(maxMarkersSize.width(), siz.width()),
00975 qMax(maxMarkersSize.height(), siz.height()));
00976 }
00977 }
00978
00979
00980
00981
00982
00983
00984 const int markerOffsOnLine = 8;
00985
00986 int maxLineLength = 18;
00987 {
00988 bool hasComplexPenStyle = false;
00989 for ( int dataset = 0; dataset < d->modelLabels.count(); ++dataset ){
00990 const QPen pn = pen(dataset);
00991 const Qt::PenStyle ps = pn.style();
00992 if( ps != Qt::NoPen ){
00993 maxLineLength = qMax( pn.width() * 18, maxLineLength );
00994 if( ps != Qt::SolidLine )
00995 hasComplexPenStyle = true;
00996 }
00997 }
00998 if( hasComplexPenStyle && bShowMarkers )
00999 maxLineLength =
01000 maxLineLength + markerOffsOnLine +
01001 static_cast<int>(maxMarkersSize.width());
01002 }
01003
01004 #define ADD_MARKER_SPACER_FOR_HORIZONTAL_MODE( column ) \
01005 { \
01006 if( orientation() != Qt::Vertical ) \
01007 d->layout->addItem( new QSpacerItem( spacing(), 1 ), \
01008 2, \
01009 column ); \
01010 }
01011
01012
01013 ADD_MARKER_SPACER_FOR_HORIZONTAL_MODE( 0 )
01014
01015
01016 for ( int dataset = 0; dataset < d->modelLabels.count(); ++dataset ) {
01017 KDChart::AbstractLayoutItem* markerLineItem = 0;
01018
01019
01020
01021 const QBrush markerBrush = markerAttrs[dataset].markerColor().isValid() ?
01022 QBrush(markerAttrs[dataset].markerColor()) : brush( dataset );
01023 switch( style ){
01024 case( MarkersOnly ):
01025 markerLineItem = new KDChart::MarkerLayoutItem(
01026 diagram(),
01027 markerAttrs[dataset],
01028 markerBrush,
01029 markerAttrs[dataset].pen(),
01030 Qt::AlignLeft );
01031 break;
01032 case( LinesOnly ):
01033 markerLineItem = new KDChart::LineLayoutItem(
01034 diagram(),
01035 maxLineLength,
01036 pen( dataset ),
01037 Qt::AlignCenter );
01038 break;
01039 case( MarkersAndLines ):
01040 markerLineItem = new KDChart::LineWithMarkerLayoutItem(
01041 diagram(),
01042 maxLineLength,
01043 pen( dataset ),
01044 markerOffsOnLine,
01045 markerAttrs[dataset],
01046 markerBrush,
01047 markerAttrs[dataset].pen(),
01048 Qt::AlignCenter );
01049 break;
01050 default:
01051 Q_ASSERT( false );
01052 }
01053 if( markerLineItem ){
01054 d->layoutItems << markerLineItem;
01055 if( orientation() == Qt::Vertical )
01056 d->layout->addItem( markerLineItem,
01057 dataset*2+2,
01058 1,
01059 1, 1, Qt::AlignCenter );
01060 else
01061 d->layout->addItem( markerLineItem,
01062 2,
01063 dataset*4+1 );
01064 }
01065
01066
01067 KDChart::TextLayoutItem* labelItem =
01068 new KDChart::TextLayoutItem( text( dataset ),
01069 labelAttrs,
01070 referenceArea(), orient,
01071 d->textAlignment );
01072 labelItem->setParentWidget( this );
01073
01074 d->layoutItems << labelItem;
01075 if( orientation() == Qt::Vertical )
01076 d->layout->addItem( labelItem,
01077 dataset*2+2,
01078 3 );
01079 else
01080 d->layout->addItem( labelItem,
01081 2,
01082 dataset*4+2 );
01083
01084
01085 if( orientation() == Qt::Vertical && showLines() && dataset != d->modelLabels.count()-1 ) {
01086 KDChart::HorizontalLineLayoutItem* lineItem = new KDChart::HorizontalLineLayoutItem();
01087 d->layoutItems << lineItem;
01088 d->layout->addItem( lineItem,
01089 dataset*2+1+2,
01090 0,
01091 1, 5, Qt::AlignCenter );
01092 }
01093
01094
01095 if( orientation() == Qt::Horizontal && showLines() && dataset != d->modelLabels.count()-1 ) {
01096 KDChart::VerticalLineLayoutItem* lineItem = new KDChart::VerticalLineLayoutItem();
01097 d->layoutItems << lineItem;
01098 d->layout->addItem( lineItem,
01099 2,
01100 style == MarkersAndLines ? dataset*4+4 : dataset*4+3 ,
01101 1, 1, Qt::AlignCenter );
01102 }
01103
01104
01105 ADD_MARKER_SPACER_FOR_HORIZONTAL_MODE( dataset*4+4 )
01106 }
01107
01108
01109 if( orientation() == Qt::Vertical && showLines() && d->modelLabels.count() ) {
01110 KDChart::VerticalLineLayoutItem* lineItem = new KDChart::VerticalLineLayoutItem();
01111 d->layoutItems << lineItem;
01112 d->layout->addItem( lineItem, 2, 2, d->modelLabels.count()*2, 1 );
01113 }
01114
01115
01116 activateTheLayout();
01117
01118 emit propertiesChanged();
01119
01120
01121 #ifdef DEBUG_LEGEND_PAINT
01122 qDebug() << "leaving Legend::buildLegend()";
01123 #endif
01124 }
01125
01126 void Legend::setHiddenDatasets( const QList<uint> hiddenDatasets )
01127 {
01128 d->hiddenDatasets = hiddenDatasets;
01129 }
01130
01131 const QList<uint> Legend::hiddenDatasets() const
01132 {
01133 return d->hiddenDatasets;
01134 }
01135
01136 void Legend::setDatasetHidden( uint dataset, bool hidden )
01137 {
01138 if( hidden && !d->hiddenDatasets.contains( dataset ) )
01139 d->hiddenDatasets.append( dataset );
01140 else if( !hidden && d->hiddenDatasets.contains( dataset ) )
01141 d->hiddenDatasets.removeAll( dataset );
01142 }
01143
01144 bool Legend::datasetIsHidden( uint dataset ) const
01145 {
01146 return d->hiddenDatasets.contains( dataset );
01147 }
01148