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