KD Chart API Documentation  3.1
KDChartAbstractDiagram.cpp
Go to the documentation of this file.
1 /****************************************************************************
2 **
3 ** This file is part of the KD Chart library.
4 **
5 ** SPDX-FileCopyrightText: 2001 Klarälvdalens Datakonsult AB, a KDAB Group company <info@kdab.com>
6 **
7 ** SPDX-License-Identifier: MIT
8 **
9 ****************************************************************************/
10 
11 #include "KDChartAbstractDiagram.h"
12 #include "KDChartAbstractDiagram_p.h"
13 
14 #include <QAbstractProxyModel>
15 #include <QApplication>
16 #include <QDebug>
17 #include <QPainter>
18 #include <QSizeF>
19 
22 #include "KDChartChart.h"
25 #include "KDChartPainterSaver_p.h"
26 #include "KDChartTextAttributes.h"
28 
29 #include <KDABLibFakes>
30 
31 #include <limits>
32 
33 using namespace KDChart;
34 
35 #define d d_func()
36 
38  : QAbstractItemView(parent)
39  , _d(new Private())
40 {
41  _d->init(plane);
42  init();
43 }
44 
46 {
47  Q_EMIT aboutToBeDestroyed();
48  delete _d;
49 }
50 
51 void AbstractDiagram::init()
52 {
53  _d->diagram = this;
54  d->reverseMapper.setDiagram(this);
55 }
56 
57 bool AbstractDiagram::compare(const AbstractDiagram *other) const
58 {
59  if (other == this)
60  return true;
61  if (!other) {
62  return false;
63  }
64  return // compare QAbstractScrollArea properties
65  (horizontalScrollBarPolicy() == other->horizontalScrollBarPolicy()) && (verticalScrollBarPolicy() == other->verticalScrollBarPolicy()) &&
66  // compare QFrame properties
67  (frameShadow() == other->frameShadow()) && (frameShape() == other->frameShape()) &&
68  // frameWidth is a read-only property defined by the style, it should not be in here:
69  // (frameWidth() == other->frameWidth()) &&
70  (lineWidth() == other->lineWidth()) && (midLineWidth() == other->midLineWidth()) &&
71  // compare QAbstractItemView properties
72  (alternatingRowColors() == other->alternatingRowColors()) && (hasAutoScroll() == other->hasAutoScroll()) && (dragDropMode() == other->dragDropMode()) && (dragDropOverwriteMode() == other->dragDropOverwriteMode()) && (horizontalScrollMode() == other->horizontalScrollMode()) && (verticalScrollMode() == other->verticalScrollMode()) && (dragEnabled() == other->dragEnabled()) && (editTriggers() == other->editTriggers()) && (iconSize() == other->iconSize()) && (selectionBehavior() == other->selectionBehavior()) && (selectionMode() == other->selectionMode()) && (showDropIndicator() == other->showDropIndicator()) && (tabKeyNavigation() == other->tabKeyNavigation()) && (textElideMode() == other->textElideMode()) &&
73  // compare all of the properties stored in the attributes model
75  // compare own properties
76  (rootIndex().column() == other->rootIndex().column()) && (rootIndex().row() == other->rootIndex().row()) && (allowOverlappingDataValueTexts() == other->allowOverlappingDataValueTexts()) && (antiAliasing() == other->antiAliasing()) && (percentMode() == other->percentMode()) && (datasetDimension() == other->datasetDimension());
77 }
78 
80 {
81  return d->plane;
82 }
83 
84 const QPair<QPointF, QPointF> AbstractDiagram::dataBoundaries() const
85 {
86  if (d->databoundariesDirty) {
87  d->databoundaries = calculateDataBoundaries();
88  d->databoundariesDirty = false;
89  }
90  return d->databoundaries;
91 }
92 
94 {
95  d->databoundariesDirty = true;
96  update();
97 }
98 
99 void AbstractDiagram::setModel(QAbstractItemModel *newModel)
100 {
101  if (newModel == model()) {
102  return;
103  }
104 
105  AttributesModel *amodel = new PrivateAttributesModel(newModel, this);
106  amodel->initFrom(d->attributesModel);
107  d->setAttributesModel(amodel);
108 
109  QAbstractItemView::setModel(newModel);
110 
111  QAbstractItemModel *oldModel = QAbstractItemView::model();
112  if (oldModel != nullptr) {
113  disconnect(oldModel, &QAbstractItemModel::modelReset, this, &AbstractDiagram::doItemsLayout);
114  }
115  connect(newModel, &QAbstractItemModel::modelReset, this, &AbstractDiagram::doItemsLayout);
116 
117  scheduleDelayedItemsLayout();
119  Q_EMIT modelsChanged();
120 }
121 
122 void AbstractDiagram::setSelectionModel(QItemSelectionModel *newSelectionModel)
123 {
124  if (selectionModel()) {
125  disconnect(selectionModel(), &QItemSelectionModel::currentChanged, this, &AbstractDiagram::modelsChanged);
126  disconnect(selectionModel(), &QItemSelectionModel::selectionChanged, this, &AbstractDiagram::modelsChanged);
127  }
128  QAbstractItemView::setSelectionModel(newSelectionModel);
129  if (selectionModel()) {
130  connect(selectionModel(), &QItemSelectionModel::currentChanged, this, &AbstractDiagram::modelsChanged);
131  connect(selectionModel(), &QItemSelectionModel::selectionChanged, this, &AbstractDiagram::modelsChanged);
132  }
133  Q_EMIT modelsChanged();
134 }
135 
144 {
145  if (amodel->sourceModel() != model()) {
146  qWarning("KDChart::AbstractDiagram::setAttributesModel() failed: "
147  "Trying to set an attributesmodel which works on a different "
148  "model than the diagram.");
149  return;
150  }
151  if (qobject_cast<PrivateAttributesModel *>(amodel)) {
152  qWarning("KDChart::AbstractDiagram::setAttributesModel() failed: "
153  "Trying to set an attributesmodel that is private to another diagram.");
154  return;
155  }
156 
157  d->setAttributesModel(amodel);
158  scheduleDelayedItemsLayout();
160  Q_EMIT modelsChanged();
161 }
162 
164 {
165  return d->usesExternalAttributesModel();
166 }
167 
169 {
170  return d->attributesModel;
171 }
172 
173 QModelIndex AbstractDiagram::conditionallyMapFromSource(const QModelIndex &index) const
174 {
175  Q_ASSERT(!index.isValid() || index.model() == attributesModel() || index.model() == attributesModel()->sourceModel());
176  return index.model() == attributesModel() ? index : attributesModel()->mapFromSource(index);
177 }
178 
180 void AbstractDiagram::setRootIndex(const QModelIndex &idx)
181 {
182  QAbstractItemView::setRootIndex(idx);
183  setAttributesModelRootIndex(d->attributesModel->mapFromSource(idx));
184 }
185 
188 {
189  d->attributesModelRootIndex = idx;
191  scheduleDelayedItemsLayout();
192 }
193 
197 {
198  if (!d->attributesModelRootIndex.isValid())
199  d->attributesModelRootIndex = d->attributesModel->mapFromSource(rootIndex());
200  return d->attributesModelRootIndex;
201 }
202 
204 {
205  d->plane = parent;
206 }
207 
209 {
210  if (d->plane) {
211  d->plane->layoutDiagrams();
212  update();
213  }
214  QAbstractItemView::doItemsLayout();
215 }
216 
217 void AbstractDiagram::dataChanged(const QModelIndex &topLeft,
218  const QModelIndex &bottomRight,
219  const QVector<int> &)
220 {
221  Q_UNUSED(topLeft);
222  Q_UNUSED(bottomRight);
223  // We are still too dumb to do intelligent updates...
225  scheduleDelayedItemsLayout();
226 }
227 
228 void AbstractDiagram::setHidden(const QModelIndex &index, bool hidden)
229 {
230  d->attributesModel->setData(
231  conditionallyMapFromSource(index),
232  QVariant::fromValue(hidden),
234  Q_EMIT dataHidden();
235 }
236 
237 void AbstractDiagram::setHidden(int dataset, bool hidden)
238 {
239  d->setDatasetAttrs(dataset, QVariant::fromValue(hidden), DataHiddenRole);
240  Q_EMIT dataHidden();
241 }
242 
243 void AbstractDiagram::setHidden(bool hidden)
244 {
245  d->attributesModel->setModelData(QVariant::fromValue(hidden), DataHiddenRole);
246  Q_EMIT dataHidden();
247 }
248 
250 {
251  return attributesModel()->modelData(DataHiddenRole).value<bool>();
252 }
253 
254 bool AbstractDiagram::isHidden(int dataset) const
255 {
256  const QVariant boolFlag(d->datasetAttrs(dataset, DataHiddenRole));
257  if (boolFlag.isValid())
258  return boolFlag.value<bool>();
259  return isHidden();
260 }
261 
262 bool AbstractDiagram::isHidden(const QModelIndex &index) const
263 {
264  const QVariant boolFlag(attributesModel()->data(conditionallyMapFromSource(index),
265  DataHiddenRole));
266  if (boolFlag.isValid()) {
267  return boolFlag.value<bool>();
268  }
269  int dataset = index.column() / d->datasetDimension;
270  return isHidden(dataset);
271 }
272 
273 void AbstractDiagram::setDataValueAttributes(const QModelIndex &index,
274  const DataValueAttributes &a)
275 {
276  d->attributesModel->setData(conditionallyMapFromSource(index), QVariant::fromValue(a),
278  Q_EMIT propertiesChanged();
279 }
280 
282 {
283  d->setDatasetAttrs(dataset, QVariant::fromValue(a), DataValueLabelAttributesRole);
284  Q_EMIT propertiesChanged();
285 }
286 
288 {
290 }
291 
293 {
294  /*
295  The following did not work!
296  (khz, 2008-01-25)
297  If there was some attrs specified for the 0-th cells of a dataset,
298  then this logic would return the cell's settings instead of the header settings:
299 
300  return qVariantValue<DataValueAttributes>(
301  attributesModel()->data( attributesModel()->mapFromSource(columnToIndex( column )),
302  KDChart::DataValueLabelAttributesRole ) );
303  */
304 
305  const QVariant headerAttrs(
306  d->datasetAttrs(dataset, KDChart::DataValueLabelAttributesRole));
307  if (headerAttrs.isValid())
308  return headerAttrs.value<DataValueAttributes>();
309  return dataValueAttributes();
310 }
311 
313 {
314  return attributesModel()->data(
315  conditionallyMapFromSource(index),
317  .value<DataValueAttributes>();
318 }
319 
321 {
322  d->attributesModel->setModelData(QVariant::fromValue(a), DataValueLabelAttributesRole);
323  Q_EMIT propertiesChanged();
324 }
325 
327 {
329  attrs.setShowOverlappingDataLabels(allow);
330  setDataValueAttributes(attrs);
331  d->allowOverlappingDataValueTexts = allow;
332  Q_EMIT propertiesChanged();
333 }
334 
336 {
337  return d->allowOverlappingDataValueTexts;
338 }
339 
341 {
342  d->antiAliasing = enabled;
343  Q_EMIT propertiesChanged();
344 }
345 
347 {
348  return d->antiAliasing;
349 }
350 
352 {
353  d->percent = percent;
354  Q_EMIT propertiesChanged();
355 }
356 
358 {
359  return d->percent;
360 }
361 
362 void AbstractDiagram::paintDataValueText(QPainter *painter,
363  const QModelIndex &index,
364  const QPointF &pos,
365  qreal value)
366 {
367  d->paintDataValueText(painter, index, pos, value);
368 }
369 
371 {
372  if (!checkInvariants()) {
373  return;
374  }
375 
376  d->forgetAlreadyPaintedDataValues();
377  const int rowCount = model()->rowCount(rootIndex());
378  const int columnCount = model()->columnCount(rootIndex());
379  for (int column = 0; column < columnCount; column += datasetDimension()) {
380  for (int row = 0; row < rowCount; ++row) {
381  QModelIndex index = model()->index(row, column, rootIndex()); // checked
382  qreal x;
383  qreal y;
384  if (datasetDimension() == 1) {
385  x = row;
386  y = index.data().toReal();
387  } else {
388  x = index.data().toReal();
389  y = model()->index(row, column + 1, rootIndex()).data().toReal();
390  }
391  paintDataValueText(painter, index, coordinatePlane()->translate(QPointF(x, y)), y);
392  }
393  }
394 }
395 
396 void AbstractDiagram::paintMarker(QPainter *painter,
397  const DataValueAttributes &a,
398  const QModelIndex &index,
399  const QPointF &pos)
400 {
401  if (!checkInvariants() || !a.isVisible())
402  return;
403  const MarkerAttributes ma = a.markerAttributes();
404  if (!ma.isVisible())
405  return;
406 
407  const PainterSaver painterSaver(painter);
408  // the size of the marker - unscaled
409  const QSizeF maSize(ma.markerSize().width() / painter->transform().m11(),
410  ma.markerSize().height() / painter->transform().m22());
411  QBrush indexBrush(brush(index));
412  QPen indexPen(ma.pen());
413  if (ma.markerColor().isValid())
414  indexBrush.setColor(ma.markerColor());
415 
416  paintMarker(painter, ma, indexBrush, indexPen, pos, maSize);
417 
418  // workaround: BC cannot be changed, otherwise we would pass the
419  // index down to next-lower paintMarker function. So far, we
420  // basically save a circle of radius maSize at pos in the
421  // reverseMapper. This means that ^^^ this version of paintMarker
422  // needs to be called to reverse-map the marker.
423  d->reverseMapper.addCircle(index.row(), index.column(), pos, 2 * maSize);
424 }
425 
426 void AbstractDiagram::paintMarker(QPainter *painter,
427  const QModelIndex &index,
428  const QPointF &pos)
429 {
430  if (!checkInvariants())
431  return;
432  paintMarker(painter, dataValueAttributes(index), index, pos);
433 }
434 
435 void AbstractDiagram::paintMarker(QPainter *painter,
436  const MarkerAttributes &markerAttributes,
437  const QBrush &brush,
438  const QPen &pen,
439  const QPointF &pos,
440  const QSizeF &maSize)
441 {
442  const QPen oldPen(painter->pen());
443  // Pen is used to paint 4Pixels - 1 Pixel - Ring and FastCross types.
444  // make sure to use the brush color - see above in those cases.
445  const bool isFourPixels = (markerAttributes.markerStyle() == MarkerAttributes::Marker4Pixels);
446  if (isFourPixels || (markerAttributes.markerStyle() == MarkerAttributes::Marker1Pixel)) {
447  // for high-performance point charts with tiny point markers:
448  painter->setPen(PrintingParameters::scalePen(QPen(brush.color().lighter())));
449  if (isFourPixels) {
450  const qreal x = pos.x();
451  const qreal y = pos.y();
452  painter->drawLine(QPointF(x - 1.0, y - 1.0),
453  QPointF(x + 1.0, y - 1.0));
454  painter->drawLine(QPointF(x - 1.0, y),
455  QPointF(x + 1.0, y));
456  painter->drawLine(QPointF(x - 1.0, y + 1.0),
457  QPointF(x + 1.0, y + 1.0));
458  }
459  painter->drawPoint(pos);
460  } else {
461  const PainterSaver painterSaver(painter);
462  QPen painterPen(pen);
463  painter->setPen(PrintingParameters::scalePen(painterPen));
464  painter->setBrush(brush);
465  painter->setRenderHint(QPainter::Antialiasing);
466  painter->translate(pos);
467  switch (markerAttributes.markerStyle()) {
469  if (markerAttributes.threeD()) {
470  QRadialGradient grad;
471  grad.setCoordinateMode(QGradient::ObjectBoundingMode);
472  QColor drawColor = brush.color();
473  grad.setCenter(0.5, 0.5);
474  grad.setRadius(1.0);
475  grad.setFocalPoint(0.35, 0.35);
476  grad.setColorAt(0.00, drawColor.lighter(150));
477  grad.setColorAt(0.20, drawColor);
478  grad.setColorAt(0.50, drawColor.darker(150));
479  grad.setColorAt(0.75, drawColor.darker(200));
480  grad.setColorAt(0.95, drawColor.darker(250));
481  grad.setColorAt(1.00, drawColor.darker(200));
482  QBrush newBrush(grad);
483  newBrush.setTransform(brush.transform());
484  painter->setBrush(newBrush);
485  }
486  painter->drawEllipse(QRectF(0 - maSize.height() / 2, 0 - maSize.width() / 2,
487  maSize.height(), maSize.width()));
488  } break;
490  QRectF rect(0 - maSize.width() / 2, 0 - maSize.height() / 2,
491  maSize.width(), maSize.height());
492  painter->drawRect(rect);
493  break;
494  }
496  QVector<QPointF> diamondPoints;
497  QPointF top, left, bottom, right;
498  top = QPointF(0, 0 - maSize.height() / 2);
499  left = QPointF(0 - maSize.width() / 2, 0);
500  bottom = QPointF(0, maSize.height() / 2);
501  right = QPointF(maSize.width() / 2, 0);
502  diamondPoints << top << left << bottom << right;
503  painter->drawPolygon(diamondPoints);
504  break;
505  }
506  // both handled on top of the method:
509  break;
511  painter->setBrush(Qt::NoBrush);
512  painter->setPen(PrintingParameters::scalePen(QPen(brush.color())));
513  painter->drawEllipse(QRectF(0 - maSize.height() / 2, 0 - maSize.width() / 2,
514  maSize.height(), maSize.width()));
515  break;
516  }
518  // Note: Markers can have outline,
519  // so just drawing two rects is NOT the solution here!
520  const qreal w02 = maSize.width() * 0.2;
521  const qreal w05 = maSize.width() * 0.5;
522  const qreal h02 = maSize.height() * 0.2;
523  const qreal h05 = maSize.height() * 0.5;
524  QVector<QPointF> crossPoints;
525  QPointF p[12];
526  p[0] = QPointF(-w02, -h05);
527  p[1] = QPointF(w02, -h05);
528  p[2] = QPointF(w02, -h02);
529  p[3] = QPointF(w05, -h02);
530  p[4] = QPointF(w05, h02);
531  p[5] = QPointF(w02, h02);
532  p[6] = QPointF(w02, h05);
533  p[7] = QPointF(-w02, h05);
534  p[8] = QPointF(-w02, h02);
535  p[9] = QPointF(-w05, h02);
536  p[10] = QPointF(-w05, -h02);
537  p[11] = QPointF(-w02, -h02);
538  for (int i = 0; i < 12; ++i)
539  crossPoints << p[i];
540  crossPoints << p[0];
541  painter->drawPolygon(crossPoints);
542  break;
543  }
545  QPointF left, right, top, bottom;
546  left = QPointF(-maSize.width() / 2, 0);
547  right = QPointF(maSize.width() / 2, 0);
548  top = QPointF(0, -maSize.height() / 2);
549  bottom = QPointF(0, maSize.height() / 2);
550  painter->setPen(PrintingParameters::scalePen(QPen(brush.color())));
551  painter->drawLine(left, right);
552  painter->drawLine(top, bottom);
553  break;
554  }
556  break;
558  QPainterPath path = markerAttributes.customMarkerPath();
559  const QRectF pathBoundingRect = path.boundingRect();
560  const qreal xScaling = maSize.height() / pathBoundingRect.height();
561  const qreal yScaling = maSize.width() / pathBoundingRect.width();
562  const qreal scaling = qMin(xScaling, yScaling);
563  painter->scale(scaling, scaling);
564  painter->setPen(PrintingParameters::scalePen(QPen(brush.color())));
565  painter->drawPath(path);
566  break;
567  }
568  default:
569  Q_ASSERT_X(false, "paintMarkers()",
570  "Type item does not match a defined Marker Type.");
571  }
572  }
573  painter->setPen(oldPen);
574 }
575 
576 void AbstractDiagram::paintMarkers(QPainter *painter)
577 {
578  if (!checkInvariants()) {
579  return;
580  }
581 
582  const int rowCount = model()->rowCount(rootIndex());
583  const int columnCount = model()->columnCount(rootIndex());
584  for (int column = 0; column < columnCount; column += datasetDimension()) {
585  for (int row = 0; row < rowCount; ++row) {
586  QModelIndex index = model()->index(row, column, rootIndex()); // checked
587  qreal x;
588  qreal y;
589  if (datasetDimension() == 1) {
590  x = row;
591  y = index.data().toReal();
592  } else {
593  x = index.data().toReal();
594  y = model()->index(row, column + 1, rootIndex()).data().toReal();
595  }
596  paintMarker(painter, index, coordinatePlane()->translate(QPointF(x, y)));
597  }
598  }
599 }
600 
601 void AbstractDiagram::setPen(const QModelIndex &index, const QPen &pen)
602 {
604  conditionallyMapFromSource(index),
605  QVariant::fromValue(pen), DatasetPenRole);
606  Q_EMIT propertiesChanged();
607 }
608 
609 void AbstractDiagram::setPen(const QPen &pen)
610 {
612  QVariant::fromValue(pen), DatasetPenRole);
613  Q_EMIT propertiesChanged();
614 }
615 
616 void AbstractDiagram::setPen(int dataset, const QPen &pen)
617 {
618  d->setDatasetAttrs(dataset, QVariant::fromValue(pen), DatasetPenRole);
619  Q_EMIT propertiesChanged();
620 }
621 
623 {
624  return attributesModel()->data(DatasetPenRole).value<QPen>();
625 }
626 
627 QPen AbstractDiagram::pen(int dataset) const
628 {
629  const QVariant penSettings(d->datasetAttrs(dataset, DatasetPenRole));
630  if (penSettings.isValid())
631  return penSettings.value<QPen>();
632  return pen();
633 }
634 
635 QPen AbstractDiagram::pen(const QModelIndex &index) const
636 {
637  return attributesModel()->data(
638  conditionallyMapFromSource(index),
640  .value<QPen>();
641 }
642 
643 void AbstractDiagram::setBrush(const QModelIndex &index, const QBrush &brush)
644 {
646  conditionallyMapFromSource(index),
647  QVariant::fromValue(brush), DatasetBrushRole);
648  Q_EMIT propertiesChanged();
649 }
650 
651 void AbstractDiagram::setBrush(const QBrush &brush)
652 {
654  QVariant::fromValue(brush), DatasetBrushRole);
655  Q_EMIT propertiesChanged();
656 }
657 
658 void AbstractDiagram::setBrush(int dataset, const QBrush &brush)
659 {
660  d->setDatasetAttrs(dataset, QVariant::fromValue(brush), DatasetBrushRole);
661  Q_EMIT propertiesChanged();
662 }
663 
665 {
666  return attributesModel()->data(DatasetBrushRole).value<QBrush>();
667 }
668 
669 QBrush AbstractDiagram::brush(int dataset) const
670 {
671  const QVariant brushSettings(d->datasetAttrs(dataset, DatasetBrushRole));
672  if (brushSettings.isValid())
673  return brushSettings.value<QBrush>();
674  return brush();
675 }
676 
677 QBrush AbstractDiagram::brush(const QModelIndex &index) const
678 {
679  return attributesModel()->data(conditionallyMapFromSource(index), DatasetBrushRole).value<QBrush>();
680 }
681 
688 void AbstractDiagram::setUnitPrefix(const QString &prefix, int column, Qt::Orientation orientation)
689 {
690  d->unitPrefixMap[column][orientation] = prefix;
691 }
692 
698 void AbstractDiagram::setUnitPrefix(const QString &prefix, Qt::Orientation orientation)
699 {
700  d->unitPrefix[orientation] = prefix;
701 }
702 
709 void AbstractDiagram::setUnitSuffix(const QString &suffix, int column, Qt::Orientation orientation)
710 {
711  d->unitSuffixMap[column][orientation] = suffix;
712 }
713 
719 void AbstractDiagram::setUnitSuffix(const QString &suffix, Qt::Orientation orientation)
720 {
721  d->unitSuffix[orientation] = suffix;
722 }
723 
731 QString AbstractDiagram::unitPrefix(int column, Qt::Orientation orientation, bool fallback) const
732 {
733  if (!fallback || d->unitPrefixMap[column].contains(orientation))
734  return d->unitPrefixMap[column][orientation];
735  return d->unitPrefix[orientation];
736 }
737 
742 QString AbstractDiagram::unitPrefix(Qt::Orientation orientation) const
743 {
744  return d->unitPrefix[orientation];
745 }
746 
754 QString AbstractDiagram::unitSuffix(int column, Qt::Orientation orientation, bool fallback) const
755 {
756  if (!fallback || d->unitSuffixMap[column].contains(orientation))
757  return d->unitSuffixMap[column][orientation];
758  return d->unitSuffix[orientation];
759 }
760 
765 QString AbstractDiagram::unitSuffix(Qt::Orientation orientation) const
766 {
767  return d->unitSuffix[orientation];
768 }
769 
770 // implement QAbstractItemView:
771 QRect AbstractDiagram::visualRect(const QModelIndex &index) const
772 {
773  return d->reverseMapper.boundingRect(index.row(), index.column()).toRect();
774 }
775 
776 void AbstractDiagram::scrollTo(const QModelIndex &, ScrollHint)
777 {
778 }
779 
780 // indexAt ... down below
781 
782 QModelIndex AbstractDiagram::moveCursor(CursorAction, Qt::KeyboardModifiers)
783 {
784  return QModelIndex();
785 }
786 
788 {
789  return 0;
790 }
791 
793 {
794  return 0;
795 }
796 
797 bool AbstractDiagram::isIndexHidden(const QModelIndex &) const
798 {
799  return true;
800 }
801 
802 void AbstractDiagram::setSelection(const QRect &rect, QItemSelectionModel::SelectionFlags command)
803 {
804  const QModelIndexList indexes = d->indexesIn(rect);
805  QItemSelection selection;
806  for (const QModelIndex &index : indexes) {
807  selection.append(QItemSelectionRange(index));
808  }
809  selectionModel()->select(selection, command);
810 }
811 
812 QRegion AbstractDiagram::visualRegionForSelection(const QItemSelection &selection) const
813 {
814  QPolygonF polygon;
815  const auto constIndexes = selection.indexes();
816  for (const QModelIndex &index : constIndexes) {
817  polygon << d->reverseMapper.polygon(index.row(), index.column());
818  }
819  return polygon.isEmpty() ? QRegion() : QRegion(polygon.toPolygon());
820 }
821 
822 QRegion AbstractDiagram::visualRegion(const QModelIndex &index) const
823 {
824  QPolygonF polygon = d->reverseMapper.polygon(index.row(), index.column());
825  return polygon.isEmpty() ? QRegion() : QRegion(polygon.toPolygon());
826 }
827 
829 {
830  d->attributesModel->setPaletteType(AttributesModel::PaletteTypeDefault);
831 }
832 
834 {
835  d->attributesModel->setPaletteType(AttributesModel::PaletteTypeSubdued);
836 }
837 
839 {
840  d->attributesModel->setPaletteType(AttributesModel::PaletteTypeRainbow);
841 }
842 
844 {
845  QStringList ret;
846  if (model()) {
847  // qDebug() << "AbstractDiagram::itemRowLabels(): " << attributesModel()->rowCount(attributesModelRootIndex()) << "entries";
848  const int rowCount = attributesModel()->rowCount(attributesModelRootIndex());
849  for (int i = 0; i < rowCount; ++i) {
850  // qDebug() << "item row label: " << attributesModel()->headerData( i, Qt::Vertical, Qt::DisplayRole ).toString();
851  ret << unitPrefix(i, Qt::Horizontal, true) + attributesModel()->headerData(i, Qt::Vertical, Qt::DisplayRole).toString() + unitSuffix(i, Qt::Horizontal, true);
852  }
853  }
854  return ret;
855 }
856 
858 {
859  QStringList ret;
860  if (!model()) {
861  return ret;
862  }
863  const int datasetCount = d->datasetCount();
864  for (int i = 0; i < datasetCount; ++i) {
865  ret << d->datasetAttrs(i, Qt::DisplayRole).toString();
866  }
867  return ret;
868 }
869 
870 QList<QBrush> AbstractDiagram::datasetBrushes() const
871 {
872  QList<QBrush> ret;
873  if (!model()) {
874  return ret;
875  }
876  const int datasetCount = d->datasetCount();
877  for (int i = 0; i < datasetCount; ++i) {
878  ret << brush(i);
879  }
880  return ret;
881 }
882 
883 QList<QPen> AbstractDiagram::datasetPens() const
884 {
885  QList<QPen> ret;
886  if (!model()) {
887  return ret;
888  }
889  const int datasetCount = d->datasetCount();
890  for (int i = 0; i < datasetCount; ++i) {
891  ret << pen(i);
892  }
893  return ret;
894 }
895 
896 QList<MarkerAttributes> AbstractDiagram::datasetMarkers() const
897 {
898  QList<MarkerAttributes> ret;
899  if (!model()) {
900  return ret;
901  }
902  const int datasetCount = d->datasetCount();
903  for (int i = 0; i < datasetCount; ++i) {
905  }
906  return ret;
907 }
908 
909 bool AbstractDiagram::checkInvariants(bool justReturnTheStatus) const
910 {
911  if (!justReturnTheStatus) {
912  Q_ASSERT_X(model(), "AbstractDiagram::checkInvariants()",
913  "There is no usable model set, for the diagram.");
914 
915  Q_ASSERT_X(coordinatePlane(), "AbstractDiagram::checkInvariants()",
916  "There is no usable coordinate plane set, for the diagram.");
917  }
918  return model() && coordinatePlane();
919 }
920 
922 {
923  return d->datasetDimension;
924 }
925 
927 {
928  Q_UNUSED(dimension);
929  qDebug() << "Setting the dataset dimension using AbstractDiagram::setDatasetDimension is "
930  "obsolete. Use the specific diagram types instead.";
931 }
932 
934 {
935  Q_ASSERT(dimension != 0);
936  if (d->datasetDimension == dimension) {
937  return;
938  }
939  d->datasetDimension = dimension;
940  d->attributesModel->setDatasetDimension(dimension);
942  Q_EMIT layoutChanged(this);
943 }
944 
945 qreal AbstractDiagram::valueForCell(int row, int column) const
946 {
947  if (!d->attributesModel->hasIndex(row, column, attributesModelRootIndex())) {
948  qWarning() << "AbstractDiagram::valueForCell(): Requesting value for invalid index!";
949  return std::numeric_limits<qreal>::quiet_NaN();
950  }
951  return d->attributesModel->data(
952  d->attributesModel->index(row, column, attributesModelRootIndex()))
953  .toReal(); // checked
954 }
955 
957 {
958  if (d->plane) {
959  d->plane->update();
960  }
961 }
962 
963 QModelIndex AbstractDiagram::indexAt(const QPoint &point) const
964 {
965  return d->indexAt(point);
966 }
967 
968 QModelIndexList AbstractDiagram::indexesAt(const QPoint &point) const
969 {
970  return d->indexesAt(point);
971 }
972 
973 QModelIndexList AbstractDiagram::indexesIn(const QRect &rect) const
974 {
975  return d->indexesIn(rect);
976 }
#define d
Declaring the class KDChart::DataValueAttributes.
QPointF translate(const TernaryPoint &point)
Base class common for all coordinate planes, CartesianCoordinatePlane, PolarCoordinatePlane,...
AbstractDiagram defines the interface for diagram classes.
void setModel(QAbstractItemModel *model) override
void setDataValueAttributes(const QModelIndex &index, const DataValueAttributes &a)
virtual Q_DECL_DEPRECATED void paintDataValueTexts(QPainter *painter)
virtual const QPair< QPointF, QPointF > calculateDataBoundaries() const =0
virtual AttributesModel * attributesModel() const
bool compare(const AbstractDiagram *other) const
void setSelection(const QRect &rect, QItemSelectionModel::SelectionFlags command) override
int verticalOffset() const override
void setUnitPrefix(const QString &prefix, int column, Qt::Orientation orientation)
virtual bool checkInvariants(bool justReturnTheStatus=false) const
void setPen(const QModelIndex &index, const QPen &pen)
virtual void paintMarker(QPainter *painter, const MarkerAttributes &markerAttributes, const QBrush &brush, const QPen &, const QPointF &point, const QSizeF &size)
int horizontalOffset() const override
QModelIndex moveCursor(CursorAction cursorAction, Qt::KeyboardModifiers modifiers) override
DataValueAttributes dataValueAttributes() const
void paintDataValueText(QPainter *painter, const QModelIndex &index, const QPointF &pos, qreal value)
QRect visualRect(const QModelIndex &index) const override
void layoutChanged(AbstractDiagram *)
AbstractDiagram(Private *p, QWidget *parent, AbstractCoordinatePlane *plane)
QModelIndex attributesModelRootIndex() const
returns a QModelIndex pointing into the AttributesModel that corresponds to the root index of the dia...
const QPair< QPointF, QPointF > dataBoundaries() const
Return the bottom left and top right data point, that the diagram will display (unless the grid adjus...
void scrollTo(const QModelIndex &index, ScrollHint hint=EnsureVisible) override
void dataChanged(const QModelIndex &topLeft, const QModelIndex &bottomRight, const QVector< int > &roles=QVector< int >()) override
QList< QBrush > datasetBrushes() const
virtual void setAttributesModel(AttributesModel *model)
Sets an external AttributesModel on this diagram.
Q_DECL_DEPRECATED qreal valueForCell(int row, int column) const
QString unitPrefix(int column, Qt::Orientation orientation, bool fallback=false) const
AbstractCoordinatePlane * coordinatePlane() const
void setHidden(const QModelIndex &index, bool hidden)
bool isIndexHidden(const QModelIndex &index) const override
QList< QPen > datasetPens() const
void setUnitSuffix(const QString &suffix, int column, Qt::Orientation orientation)
QModelIndexList indexesIn(const QRect &rect) const
void setBrush(const QModelIndex &index, const QBrush &brush)
Q_DECL_DEPRECATED void setPercentMode(bool percent)
Deprecated method that turns the percent mode of this diagram on or off.
void setAllowOverlappingDataValueTexts(bool allow)
bool percentMode() const
Returns whether this diagram is drawn in percent mode.
void setSelectionModel(QItemSelectionModel *selectionModel) override
Q_DECL_DEPRECATED void setDatasetDimension(int dimension)
virtual bool usesExternalAttributesModel() const
virtual void setCoordinatePlane(AbstractCoordinatePlane *plane)
QModelIndex indexAt(const QPoint &point) const override
QModelIndexList indexesAt(const QPoint &point) const
void setRootIndex(const QModelIndex &idx) override
Reimplemented for internal purposes.
virtual QRegion visualRegion(const QModelIndex &index) const
virtual Q_DECL_DEPRECATED void paintMarkers(QPainter *painter)
QList< MarkerAttributes > datasetMarkers() const
QString unitSuffix(int column, Qt::Orientation orientation, bool fallback=false) const
void setAttributesModelRootIndex(const QModelIndex &)
void setDatasetDimensionInternal(int dimension)
QRegion visualRegionForSelection(const QItemSelection &selection) const override
QModelIndex mapFromSource(const QModelIndex &sourceIndex) const override
Reimplemented for internal purposes.
A proxy model used for decorating data with attributes.
QVariant data(int role) const
int rowCount(const QModelIndex &) const override
QVariant modelData(int role) const
void initFrom(const AttributesModel *other)
bool compare(const AttributesModel *other) const
bool setData(const QModelIndex &index, const QVariant &value, int role=Qt::DisplayRole) override
QVariant headerData(int section, Qt::Orientation orientation, int role=Qt::DisplayRole) const override
bool setModelData(const QVariant value, int role)
Diagram attributes dealing with data value labels.
void setShowOverlappingDataLabels(bool showOverlappingDataLabels)
A set of attributes controlling the appearance of data set markers.
static QPen scalePen(const QPen &pen)
Internally used class just adding a special constructor used by AbstractDiagram.
@ DataValueLabelAttributesRole
@ DataHiddenRole
@ DatasetBrushRole
@ DatasetPenRole

© 2001 Klarälvdalens Datakonsult AB (KDAB)
"The Qt, C++ and OpenGL Experts"
https://www.kdab.com/
https://www.kdab.com/development-resources/qt-tools/kd-chart/
Generated by doxygen 1.9.1