13#include "KDChartLegend_p.h"
21#include <QAbstractTextDocumentLayout>
26#include <QTextCharFormat>
28#include <QTextDocumentFragment>
29#include <QTextTableCell>
33#include <KDABLibFakes>
37Legend::Private::Private()
42 , titleText(
QObject::tr(
"Legend"))
53Legend::Private::~Private()
85 d->layout->setContentsMargins(2, 2, 2, 2);
86 d->layout->setSpacing(
d->spacing);
96 textAttrs.setMinimalFontSize(minimalFontSize);
125#ifdef DEBUG_LEGEND_PAINT
126 qDebug() <<
"Legend::sizeHint() started";
141#ifdef DEBUG_LEGEND_PAINT
142 qDebug() <<
"Legend::resizeLayout started";
145 d->reflowHDatasetItems(
this);
149#ifdef DEBUG_LEGEND_PAINT
150 qDebug() <<
"Legend::resizeLayout done";
154void Legend::activateTheLayout()
156 if (
d->layout &&
d->layout->parent()) {
157 d->layout->activate();
163 if (
d->legendStyle ==
style) {
172 return d->legendStyle;
180 auto *legend =
new Legend(
new Private(*
d),
nullptr);
206#ifdef DEBUG_LEGEND_PAINT
207 qDebug() <<
"entering Legend::paint( QPainter* painter )";
219#ifdef DEBUG_LEGEND_PAINT
220 qDebug() <<
"leaving Legend::paint( QPainter* painter )";
237 if (area ==
d->referenceArea) {
240 d->referenceArea = area;
251 if (
d->observers.isEmpty()) {
254 return d->observers.first()->diagram();
260 for (
int i = 0;
i <
d->observers.size(); ++
i) {
261 list <<
d->observers.
at(
i)->diagram();
269 for (
int i = 0;
i <
d->observers.size(); ++
i) {
270 list <<
d->observers.
at(
i)->diagram();
299 for (
int i = 0;
i < diagrams.
count();
i++) {
301 for (
int i = 0;
i <
oldDiagram->datasetBrushes().count();
i++) {
305 for (
int i = 0;
i <
oldDiagram->datasetPens().count();
i++) {
316 d->observers.removeOne(
oldObs);
331 for (
int i = 0;
i <
d->observers.size(); ++
i) {
343 if (!
d->observers.isEmpty() && !
old) {
344 old =
d->observers.first()->diagram();
346 d->observers.removeFirst();
361 for (
int i = 0;
i <
d->observers.count(); ++
i) {
362 if (
d->observers.at(
i)->diagram() ==
diagram) {
390 emitPositionChanged();
393void Legend::setNeedRebuild()
405 emitPositionChanged();
408void Legend::emitPositionChanged()
425 emitPositionChanged();
439 emitPositionChanged();
444 return d->textAlignment;
449 if (
d->legendLineSymbolAlignment ==
alignment) {
453 emitPositionChanged();
458 return d->legendLineSymbolAlignment;
466 emitPositionChanged();
472 return d->relativePosition;
482 emitPositionChanged();
487 return d->orientation;
497 emitPositionChanged();
512 emitPositionChanged();
524 emitPositionChanged();
529 return d->useAutomaticMarkerSize;
539 if (!
d->texts.count()) {
557 if (
d->texts.find(
dataset) !=
d->texts.end()) {
603 bool changed =
false;
605 for (
int i = 0;
i < datasetBrushes.
count();
i++) {
606 if (
d->brushes[
i] != datasetBrushes[
i]) {
607 d->brushes[
i] = datasetBrushes[
i];
629 if (
d->pens.find(
dataset) !=
d->pens.end()) {
653 if (
d->markerAttributes.find(
dataset) !=
d->markerAttributes.end()) {
654 return d->markerAttributes[
dataset];
655 }
else if (
static_cast<uint>(
d->modelMarkers.count()) >
dataset) {
664 return d->markerAttributes;
669 if (
d->textAttributes == a) {
672 d->textAttributes = a;
678 return d->textAttributes;
683 if (
d->titleText ==
text) {
697 if (
d->titleTextAttributes == a) {
700 d->titleTextAttributes = a;
706 return d->titleTextAttributes;
711#ifdef DEBUG_LEGEND_PAINT
712 qDebug() <<
"entering Legend::forceRebuild()";
715#ifdef DEBUG_LEGEND_PAINT
716 qDebug() <<
"leaving Legend::forceRebuild()";
722 if (
d->spacing == space &&
d->layout->spacing() ==
int(space)) {
726 d->layout->setSpacing(space);
738 for (
int i = 0;
i <
pal.size();
i++) {
746 for (
int i = 0;
i <
pal.size();
i++) {
755 for (
int i = 0;
i <
pal.size();
i++) {
762 0, 5, 10, 15, 2, 7, 12, 17, 4,
763 9, 14, 1, 6, 11, 16, 3, 8, 13};
773#ifdef DEBUG_LEGEND_PAINT
774 qDebug() <<
"Legend::resizeEvent() called";
781void Legend::Private::fetchPaintOptions(
Legend *q)
784 modelBrushes.clear();
786 modelMarkers.clear();
788 for (
int i = 0; i < observers.size(); ++i) {
799 int dataset = ascend ? 0 : diagramLabels.
count() - 1;
800 const int end = ascend ? diagramLabels.
count() : -1;
801 for (; dataset != end; dataset += ascend ? 1 : -1) {
805 modelLabels += diagramLabels[dataset];
806 modelBrushes += diagramBrushes[dataset];
807 modelPens += diagramPens[dataset];
808 modelMarkers += diagramMarkers[dataset];
812 Q_ASSERT(modelLabels.count() == modelBrushes.count());
815QSizeF Legend::Private::markerSize(
Legend *q,
int dataset, qreal fontHeight)
const
819 return QSizeF(fontHeight, fontHeight);
825QSizeF Legend::Private::maxMarkerSize(
Legend *q, qreal fontHeight)
const
829 for (
int dataset = 0; dataset < modelLabels.count(); ++dataset) {
830 ret = ret.expandedTo(markerSize(q, dataset, fontHeight));
836HDatasetItem::HDatasetItem()
850 w = qobject_cast<QWidget *>(w->
parent());
856void Legend::buildLegend()
863 d->destroyOldLayout();
866 d->layout->setColumnStretch(6, 1);
868 d->layout->setColumnStretch(6, 0);
871 d->fetchPaintOptions(
this);
965 dsItem.label->setParentWidget(
this);
978 d->paintItems <<
dsItem.markerLine;
992 d->flowHDatasetItems(
this);
1005#ifdef DEBUG_LEGEND_PAINT
1006 qDebug() <<
"leaving Legend::buildLegend()";
1010int HDatasetItem::height()
const
1012 return qMax(markerLine->sizeHint().height(), label->sizeHint().height());
1015void Legend::Private::reflowHDatasetItems(
Legend *q)
1017 if (hLayoutDatasets.isEmpty()) {
1024 for (
int i = layout->count() - 1; i >= 0; i--) {
1030 paintItems << alItem;
1036 for (
int j = hbox->
count() - 1; j >= 0; j--) {
1042 flowHDatasetItems(q);
1047void Legend::Private::flowHDatasetItems(
Legend *q)
1049 const int separatorLineWidth = 3;
1054 int mainLayoutRow = 1;
1055 layout->
addItem(currentLine, mainLayoutRow++, 0,
1058 for (
int dataset = 0; dataset < hLayoutDatasets.size(); dataset++) {
1059 HDatasetItem *hdsItem = &hLayoutDatasets[dataset];
1061 bool spacerUsed =
false;
1062 bool separatorUsed =
false;
1063 if (!currentLine->isEmpty()) {
1064 const int separatorWidth = (q->
showLines() ? separatorLineWidth : 0) + q->
spacing();
1065 const int payloadWidth = hdsItem->markerLine->sizeHint().width() + hdsItem->label->sizeHint().width();
1066 if (currentLine->sizeHint().width() + separatorWidth + payloadWidth > allowedWidth) {
1068#ifdef DEBUG_LEGEND_PAINT
1069 qDebug() << Q_FUNC_INFO <<
"break" << mainLayoutRow
1070 << currentLine->sizeHint().width()
1071 << currentLine->sizeHint().width() + separatorWidth + payloadWidth
1075 layout->
addItem(currentLine, mainLayoutRow++, 0,
1079 if (!hdsItem->spacer) {
1082 currentLine->addItem(hdsItem->spacer);
1086 if (!hdsItem->separatorLine) {
1089 paintItems << hdsItem->separatorLine;
1090 currentLine->addItem(hdsItem->separatorLine);
1091 separatorUsed =
true;
1097 delete hdsItem->spacer;
1098 hdsItem->spacer =
nullptr;
1100 if (!separatorUsed) {
1101 delete hdsItem->separatorLine;
1102 hdsItem->separatorLine =
nullptr;
1105 currentLine->addItem(hdsItem->markerLine);
1106 paintItems << hdsItem->markerLine;
1107 currentLine->addItem(hdsItem->label);
1108 paintItems << hdsItem->label;
1117 return !
d->hLayoutDatasets.
isEmpty();
1122 if (
d->hLayoutDatasets.isEmpty()) {
1128 for (
int i = 0;
i < 2;
i++) {
1147#ifdef DEBUG_LEGEND_PAINT
1163void Legend::Private::destroyOldLayout()
1167 for (
int i = layout->count() - 1; i >= 0; i--) {
1168 delete layout->takeAt(i);
1170 Q_ASSERT(!layout->count());
1171 hLayoutDatasets.clear();
1182 return d->hiddenDatasets;
1187 if (hidden && !
d->hiddenDatasets.contains(
dataset)) {
1189 }
else if (!hidden &&
d->hiddenDatasets.contains(
dataset)) {
1190 d->hiddenDatasets.removeAll(
dataset);
1196 return d->hiddenDatasets.contains(
dataset);
static void updateToplevelLayout(QWidget *w)
@ MeasureCalculationModeAbsolute
@ MeasureOrientationMinimum
@ MeasureOrientationHorizontal
void setFrameAttributes(const FrameAttributes &a)
bool compare(const AbstractAreaBase *other) const
FrameAttributes frameAttributes() const
AbstractDiagram defines the interface for diagram classes.
QStringList datasetLabels() const
QList< QBrush > datasetBrushes() const
QList< QPen > datasetPens() const
QList< MarkerAttributes > datasetMarkers() const
A DiagramObserver watches the associated diagram for changes and deletion and emits corresponding sig...
void diagramDataHidden(AbstractDiagram *diagram)
void diagramAboutToBeDestroyed(AbstractDiagram *diagram)
void diagramDataChanged(AbstractDiagram *diagram)
void diagramAttributesChanged(AbstractDiagram *diagram)
A set of attributes for frames around items.
void setVisible(bool visible)
static QPaintDevice * paintDevice()
Legend defines the interface for the legend drawing class.
const RelativePosition floatingPosition() const
uint datasetCount() const
void setOrientation(Qt::Orientation orientation)
void setVisible(bool visible) override
Qt::Alignment textAlignment() const
Returns the alignment used while rendering text elements within the legend.
LegendStyle legendStyle() const
bool compare(const Legend *other) const
void destroyedLegend(Legend *)
void setSortOrder(Qt::SortOrder order)
const QMap< uint, QString > texts() const
const QMap< uint, QBrush > brushes() const
void setShowLines(bool legendShowLines)
void resetTexts()
Removes all legend texts that might have been set by setText.
QSize minimumSizeHint() const override
void paint(QPainter *painter) override
DiagramList diagrams() const
void setMarkerAttributes(uint dataset, const MarkerAttributes &)
ConstDiagramList constDiagrams() const
void setDiagram(KDChart::AbstractDiagram *newDiagram)
A convenience method doing the same as replaceDiagram( newDiagram, 0 );.
void forceRebuild() override
QBrush brush(uint dataset) const
void setPosition(Position position)
Specify the position of a non-floating legend.
QString titleText() const
void setHiddenDatasets(const QList< uint > &hiddenDatasets)
void setBrushesFromDiagram(KDChart::AbstractDiagram *diagram)
TextAttributes titleTextAttributes() const
Qt::Alignment legendSymbolAlignment() const
Returns the alignment used while drawing legend symbol(alignment of Legend::LinesOnly) within the leg...
MarkerAttributes markerAttributes(uint dataset) const
void replaceDiagram(KDChart::AbstractDiagram *newDiagram, KDChart::AbstractDiagram *oldDiagram=nullptr)
uint dataSetOffset(KDChart::AbstractDiagram *diagram)
void setDatasetHidden(uint dataset, bool hidden)
void resizeEvent(QResizeEvent *event) override
void needSizeHint() override
void setUseAutomaticMarkerSize(bool useAutomaticMarkerSize)
const QMap< uint, QPen > pens() const
void setColor(uint dataset, const QColor &color)
void setLegendSymbolAlignment(Qt::Alignment)
Specify the alignment of the legend symbol( alignment of Legend::LinesOnly) within the legend.
virtual Legend * clone() const
void resizeLayout(const QSize &size) override
Qt::Orientation orientation() const
int heightForWidth(int width) const override
void addDiagram(KDChart::AbstractDiagram *newDiagram)
bool datasetIsHidden(uint dataset) const
Qt::Alignment alignment() const
void setPen(uint dataset, const QPen &pen)
QSize sizeHint() const override
void setReferenceArea(const QWidget *area)
const QWidget * referenceArea() const
void setTextAttributes(const TextAttributes &a)
void setTextAlignment(Qt::Alignment)
Specify the alignment of the text elements within the legend.
KDChart::AbstractDiagram * diagram() const
void setLegendStyle(LegendStyle style)
void removeDiagram(KDChart::AbstractDiagram *oldDiagram)
void setBrush(uint dataset, const QBrush &brush)
Position position() const
bool useAutomaticMarkerSize() const
void setSpacing(uint space)
Legend(QWidget *parent=nullptr)
void setText(uint dataset, const QString &text)
const QMap< uint, MarkerAttributes > markerAttributes() const
const QList< uint > hiddenDatasets() const
void setAlignment(Qt::Alignment)
Specify the alignment of a non-floating legend.
QPen pen(uint dataset) const
bool hasHeightForWidth() const override
void setFloatingPosition(const RelativePosition &relativePosition)
TextAttributes textAttributes() const
void setTitleTextAttributes(const TextAttributes &a)
Qt::SortOrder sortOrder() const
void setSubduedColors(bool ordered=false)
void setTitleText(const QString &text)
QString text(uint dataset) const
A set of attributes controlling the appearance of data set markers.
QSizeF markerSize() const
Measure is used to specify relative and absolute sizes in KDChart, e.g. font sizes.
A Palette is a set of brushes (or colors) to be used for painting data sets.
static const Palette & subduedPalette()
static const Palette & defaultPalette()
static const Palette & rainbowPalette()
Stores the absolute target points of a Position.
Defines a position, using compass terminology.
static const Position & Floating
static const Position & NorthEast
static const Position & NorthWest
Defines relative position information: reference area, position in this area (reference position),...
A set of text attributes.
void setPen(const QPen &pen)
qreal calculatedFontSize(const QSizeF &referenceSize, KDChartEnums::MeasureOrientation autoReferenceOrientation) const
Returns the font size that is used at drawing time.
bool isEmpty() const override
virtual int columnCount(const QModelIndex &parent) const const=0
QAbstractItemModel * model() const const
virtual void addItem(QLayoutItem *item) override
void setPointSizeF(qreal pointSize)
qreal height() const const
virtual void addItem(QLayoutItem *item)=0
virtual int count() const const=0
virtual QLayoutItem * takeAt(int index)=0
virtual QLayout * layout()
virtual QSize sizeHint() const const=0
void append(const T &value)
const T & at(int i) const const
int count(const T &value) const const
QMetaObject::Connection connect(const QObject *sender, const char *signal, const QObject *receiver, const char *method, Qt::ConnectionType type)
QObject * parent() const const
T qobject_cast(QObject *object)
bool isValid() const const