24 #include "KDChartLegend_p.h"
34 #include <QGridLayout>
36 #include <QTextTableCell>
37 #include <QTextCursor>
38 #include <QTextCharFormat>
39 #include <QTextDocumentFragment>
41 #include <QAbstractTextDocumentLayout>
45 #include <KDABLibFakes>
47 using namespace KDChart;
49 Legend::Private::Private() :
52 alignment( Qt::AlignCenter ),
53 textAlignment( Qt::AlignCenter ),
55 orientation( Qt::Vertical ),
56 order( Qt::AscendingOrder ),
60 titleText(
QObject::tr(
"Legend" ) ),
61 titleTextAttributes(),
63 useAutomaticMarkerSize( true ),
64 legendStyle( MarkersOnly )
69 relativePosition.setReferencePoints(
PositionPoints( QPointF( 0.0, 0.0 ) ) );
71 relativePosition.setAlignment( Qt::AlignTop | Qt::AlignLeft );
76 Legend::Private::~Private()
88 d->referenceArea = parent;
95 d->referenceArea = parent;
107 setSizePolicy( QSizePolicy::Fixed, QSizePolicy::Fixed );
109 d->layout =
new QGridLayout(
this );
110 d->layout->setMargin( 2 );
111 d->layout->setSpacing(
d->spacing );
119 textAttrs.
setPen( QPen( Qt::black ) );
120 textAttrs.
setFont( QFont( QLatin1String(
"helvetica" ), 10, QFont::Normal,
false ) );
126 titleTextAttrs.
setPen( QPen( Qt::black ) );
127 titleTextAttrs.
setFont( QFont( QLatin1String(
"helvetica" ), 12, QFont::Bold,
false ) );
134 frameAttrs.
setPen( QPen( Qt::black ) );
139 d->alignment = Qt::AlignCenter;
152 #ifdef DEBUG_LEGEND_PAINT
153 qDebug() <<
"Legend::sizeHint() started";
156 layoutItem->sizeHint();
158 return AbstractAreaWidget::sizeHint();
170 #ifdef DEBUG_LEGEND_PAINT
171 qDebug() <<
"Legend::resizeLayout started";
174 d->layout->setGeometry( QRect(QPoint(0,0), size) );
177 #ifdef DEBUG_LEGEND_PAINT
178 qDebug() <<
"Legend::resizeLayout done";
182 void Legend::activateTheLayout()
184 if (
d->layout &&
d->layout->parent() )
185 d->layout->activate();
191 if (
d->legendStyle == style )
return;
192 d->legendStyle = style;
198 return d->legendStyle;
221 if ( other ==
this )
return true;
226 return ( static_cast<const AbstractAreaBase*>(
this)->
compare( other ) ) &&
227 (isVisible() == other->isVisible()) &&
249 #ifdef DEBUG_LEGEND_PAINT
250 qDebug() <<
"entering Legend::paint( QPainter* painter )";
262 layoutItem->
paint( painter );
264 #ifdef DEBUG_LEGEND_PAINT
265 qDebug() <<
"leaving Legend::paint( QPainter* painter )";
272 int modelLabelsCount = 0;
278 return modelLabelsCount;
284 if ( area ==
d->referenceArea )
return;
285 d->referenceArea = area;
291 return d->referenceArea ?
d->referenceArea : qobject_cast<
const QWidget* >( parent() );
297 if (
d->observers.isEmpty() )
299 return d->observers.first()->diagram();
305 for (
int i = 0; i <
d->observers.size(); ++i)
306 list <<
d->observers.at(i)->diagram();
313 for (
int i = 0; i <
d->observers.size(); ++i)
314 list <<
d->observers.at(i)->diagram();
327 d->observers[
d->observers.indexOf( oldObs ) ] = observer;
329 d->observers.append( observer );
331 connect( observer, SIGNAL( diagramAboutToBeDestroyed(
AbstractDiagram*) ),
334 SLOT( setNeedRebuild() ));
336 SLOT( setNeedRebuild() ));
337 connect( observer, SIGNAL( diagramAttributesChanged(
AbstractDiagram*) ),
338 SLOT( setNeedRebuild() ));
345 int datasetBrushOffset = 0;
347 for (
int i =0; i <diagrams.count(); i++)
349 if (diagrams.at(i) == oldDiagram)
351 for (
int i = 0; i < oldDiagram->
datasetBrushes().count(); i++ ) {
352 d->brushes.remove(datasetBrushOffset + i);
353 d->texts.remove(datasetBrushOffset + i);
355 for (
int i = 0; i < oldDiagram->
datasetPens().count(); i++ ) {
356 d->pens.remove(datasetBrushOffset + i);
360 datasetBrushOffset += diagrams.at(i)->datasetBrushes().count();
367 d->observers.removeAt(
d->observers.indexOf( oldObs ) );
378 for (
int i = 0; i <
d->observers.size(); ++i)
379 diagrams.append(
d->observers.at(i)->diagram() );
380 for (
int i = 0; i < diagrams.count(); ++i)
388 if ( !
d->observers.isEmpty() && ! old ) {
389 old =
d->observers.first()->diagram();
391 d->observers.removeFirst();
403 for (
int i = 0; i <
d->observers.count(); ++i)
405 if (
d->observers.at(i)->diagram() ==
diagram)
409 if (!diagram->model())
412 offset = offset + diagram->model()->columnCount();
432 QWidget::setVisible( visible );
433 emitPositionChanged();
436 void Legend::setNeedRebuild()
444 if (
d->position == position )
447 emitPositionChanged();
450 void Legend::emitPositionChanged()
464 if (
d->alignment == alignment )
467 emitPositionChanged();
477 if (
d->textAlignment == alignment )
480 emitPositionChanged();
485 return d->textAlignment;
490 if (
d->legendLineSymbolAlignment == alignment)
494 emitPositionChanged();
499 return d->legendLineSymbolAlignment ;
505 if (
d->relativePosition != relativePosition ) {
506 d->relativePosition = relativePosition;
507 emitPositionChanged();
513 return d->relativePosition;
518 if (
d->orientation == orientation )
return;
521 emitPositionChanged();
526 return d->orientation;
531 if (
d->order == order )
535 emitPositionChanged();
545 if (
d->showLines == legendShowLines )
return;
546 d->showLines = legendShowLines;
548 emitPositionChanged();
560 emitPositionChanged();
565 return d->useAutomaticMarkerSize;
575 if ( !
d->texts.count() )
return;
582 if (
d->texts[ dataset ] == text )
return;
583 d->texts[ dataset ] =
text;
589 if (
d->texts.find( dataset ) !=
d->texts.end() ) {
590 return d->texts[ dataset ];
592 return d->modelLabels[ dataset ];
603 if (
d->brushes[ dataset ] != color ) {
604 d->brushes[ dataset ] = color;
612 if (
d->brushes[ dataset ] != brush ) {
613 d->brushes[ dataset ] =
brush;
621 if (
d->brushes.contains( dataset ) ) {
622 return d->brushes[ dataset ];
624 return d->modelBrushes[ dataset ];
636 bool bChangesDone =
false;
638 for (
int i = 0; i < datasetBrushes.count(); i++ ) {
639 if (
d->brushes[ i ] != datasetBrushes[ i ] ) {
640 d->brushes[ i ] = datasetBrushes[ i ];
644 if ( bChangesDone ) {
653 if (
d->pens[dataset] == pen )
return;
654 d->pens[dataset] =
pen;
661 if (
d->pens.find( dataset ) !=
d->pens.end() )
662 return d->pens[dataset];
664 return d->modelPens[ dataset ];
675 if (
d->markerAttributes[dataset] == markerAttributes )
return;
683 if (
d->markerAttributes.find( dataset ) !=
d->markerAttributes.end() )
684 return d->markerAttributes[ dataset ];
685 else if ( static_cast<uint>(
d->modelMarkers.count() ) > dataset )
686 return d->modelMarkers[ dataset ];
692 return d->markerAttributes;
698 if (
d->textAttributes == a )
return;
699 d->textAttributes = a;
705 return d->textAttributes;
710 if (
d->titleText == text )
return;
722 if (
d->titleTextAttributes == a )
return;
723 d->titleTextAttributes = a;
729 return d->titleTextAttributes;
734 #ifdef DEBUG_LEGEND_PAINT
735 qDebug() <<
"entering Legend::forceRebuild()";
739 #ifdef DEBUG_LEGEND_PAINT
740 qDebug() <<
"leaving Legend::forceRebuild()";
746 if (
d->spacing == space &&
d->layout->spacing() ==
static_cast<int>(space) )
return;
748 d->layout->setSpacing( space );
760 for (
int i = 0; i < pal.
size(); i++ ) {
768 for (
int i = 0; i < pal.
size(); i++ ) {
777 for (
int i = 0; i < pal.
size(); i++ ) {
781 static const int s_subduedColorsCount = 18;
782 Q_ASSERT( pal.
size() >= s_subduedColorsCount );
783 static const int order[ s_subduedColorsCount ] = {
784 0, 5, 10, 15, 2, 7, 12, 17, 4,
785 9, 14, 1, 6, 11, 16, 3, 8, 13
787 for (
int i = 0; i < s_subduedColorsCount; i++ ) {
796 #ifdef DEBUG_LEGEND_PAINT
797 qDebug() <<
"Legend::resizeEvent() called";
801 QTimer::singleShot(0,
this, SLOT(emitPositionChanged()));
804 void Legend::buildLegend()
807 d->layout->removeItem( layoutItem );
809 qDeleteAll(
d->layoutItems );
810 d->layoutItems.clear();
813 d->layout->setColumnStretch( 6, 1 );
815 d->layout->setColumnStretch( 6, 0 );
818 d->modelLabels.clear();
819 d->modelBrushes.clear();
820 d->modelPens.clear();
821 d->modelMarkers.clear();
823 for (
int i = 0; i <
d->observers.size(); ++i ) {
830 const int begin =
sortOrder() == Qt::AscendingOrder ? 0 : diagramLabels.count() - 1;
831 const int end =
sortOrder() == Qt::AscendingOrder ? diagramLabels.count() : -1;
832 for (
int dataset = begin; dataset != end; dataset += begin < end ? 1 : -1 ) {
836 d->modelLabels += diagramLabels[ dataset ];
837 d->modelBrushes += diagramBrushes[ dataset ];
838 d->modelPens += diagramPens[ dataset ];
839 d->modelMarkers += diagramMarkers[ dataset ];
845 Q_ASSERT(
d->modelLabels.count() ==
d->modelBrushes.count() );
857 d->layoutItems << titleItem;
859 d->layout->addItem( titleItem, 0, 0, 1, 5, Qt::AlignCenter );
861 d->layout->addItem( titleItem, 0, 0, 1,
d->modelLabels.count() ? (
d->modelLabels.count()*4) : 1, Qt::AlignCenter );
864 if (
showLines() &&
d->modelLabels.count() ) {
866 d->layoutItems << lineItem;
868 d->layout->addItem( lineItem, 1, 0, 1, 5, Qt::AlignCenter );
871 d->layout->addItem( lineItem, 1, 0, 1, 1+
d->modelLabels.count()*4, Qt::AlignCenter );
880 qreal fontHeight = labelAttrs.calculatedFontSize(
referenceArea(), orient );
882 QFont tmpFont = labelAttrs.font();
883 tmpFont.setPointSizeF( fontHeight );
888 fontHeight = metr.height();
892 QFontMetricsF metr( tmpFont );
893 fontHeight = metr.height();
897 const bool bShowMarkers = (style !=
LinesOnly);
899 QSizeF maxMarkersSize(1.0, 1.0);
901 if ( bShowMarkers ) {
902 for (
int dataset = 0; dataset <
d->modelLabels.count(); ++dataset ) {
906 ! markerAttrs[dataset].markerSize().isValid() )
908 siz = QSizeF(fontHeight, fontHeight);
909 markerAttrs[dataset].setMarkerSize( siz );
911 siz = markerAttrs[dataset].markerSize();
914 QSizeF(qMax(maxMarkersSize.width(), siz.width()),
915 qMax(maxMarkersSize.height(), siz.height()));
924 const int markerOffsOnLine = 8;
926 int maxLineLength = 18;
928 bool hasComplexPenStyle =
false;
929 for (
int dataset = 0; dataset <
d->modelLabels.count(); ++dataset ) {
930 const QPen pn =
pen(dataset);
931 const Qt::PenStyle ps = pn.style();
932 if ( ps != Qt::NoPen ) {
933 maxLineLength = qMax( pn.width() * 18, maxLineLength );
934 if ( ps != Qt::SolidLine )
935 hasComplexPenStyle =
true;
938 if ( hasComplexPenStyle && bShowMarkers )
940 maxLineLength + markerOffsOnLine +
941 static_cast<int>(maxMarkersSize.width());
946 d->layout->addItem(
new QSpacerItem(
spacing(), 1 ), 2, 0 );
950 for (
int dataset = 0; dataset <
d->modelLabels.count(); ++dataset ) {
955 const QBrush markerBrush = markerAttrs[dataset].markerColor().isValid() ?
956 QBrush(markerAttrs[dataset].markerColor()) :
brush( dataset );
961 markerAttrs[dataset],
963 markerAttrs[dataset].
pen(),
971 d->legendLineSymbolAlignment,
980 markerAttrs[dataset],
982 markerAttrs[dataset].
pen(),
988 if ( markerLineItem ) {
989 d->layoutItems << markerLineItem;
991 d->layout->addItem( markerLineItem,
994 1, 1, Qt::AlignCenter );
996 d->layout->addItem( markerLineItem,
1009 d->layoutItems << labelItem;
1011 d->layout->addItem( labelItem,
1015 d->layout->addItem( labelItem,
1022 d->layoutItems << lineItem;
1023 d->layout->addItem( lineItem,
1026 1, 5, Qt::AlignCenter );
1032 d->layoutItems << lineItem;
1033 d->layout->addItem( lineItem,
1036 1, 1, Qt::AlignCenter );
1041 d->layout->addItem(
new QSpacerItem(
spacing(), 1 ), 2, dataset * 4 + 4 );
1048 d->layoutItems << lineItem;
1049 d->layout->addItem( lineItem, 2, 2,
d->modelLabels.count()*2, 1 );
1053 activateTheLayout();
1056 #ifdef DEBUG_LEGEND_PAINT
1057 qDebug() <<
"leaving Legend::buildLegend()";
1068 return d->hiddenDatasets;
1073 if ( hidden && !
d->hiddenDatasets.contains( dataset ) )
1074 d->hiddenDatasets.append( dataset );
1075 else if ( !hidden &&
d->hiddenDatasets.contains( dataset ) )
1076 d->hiddenDatasets.removeAll( dataset );
1081 return d->hiddenDatasets.contains( dataset );