KD Chart API Documentation 3.0
Loading...
Searching...
No Matches
KDChartAttributesModel.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
12#include "KDChartGlobal.h"
13#include "KDChartPalette.h"
14
15#include <QDebug>
16#include <QPen>
17#include <QPointer>
18
34
35#include <KDABLibFakes>
36
37using namespace KDChart;
38
39class AttributesModel::Private
40{
41public:
42 Private();
43
45 QMap<int, QMap<int, QVariant>> horizontalHeaderDataMap;
46 QMap<int, QMap<int, QVariant>> verticalHeaderDataMap;
47 QMap<int, QVariant> modelDataMap;
48 QMap<int, QVariant> defaultsMap;
49 int dataDimension = 1;
51 Palette palette;
52};
53
54AttributesModel::Private::Private()
55 : palette(Palette::defaultPalette())
56{
57}
58
59#define d d_func()
60
69
71{
72 delete _d;
73 _d = nullptr;
74}
75
77{
78 *d = *other->d;
79}
80
81bool AttributesModel::compareHeaderDataMaps(const QMap<int, QMap<int, QVariant>> &mapA,
82 const QMap<int, QMap<int, QVariant>> &mapB) const
83{
84 if (mapA.count() != mapB.count()) {
85 return false;
86 }
89 for (; itA != mapA.constEnd(); ++itA, ++itB) {
90 if (itA->count() != itB->count()) {
91 return false;
92 }
95 for (; it2A != itA->constEnd(); ++it2A, ++it2B) {
96 if (it2A.key() != it2B.key()) {
97 return false;
98 }
99 if (!compareAttributes(it2A.key(), it2A.value(), it2B.value())) {
100 return false;
101 }
102 }
103 }
104 return true;
105}
106
108{
109 if (other == this) {
110 return true;
111 }
112 if (!other || d->paletteType != other->d->paletteType) {
113 return false;
114 }
115
116 {
117 if (d->dataMap.count() != other->d->dataMap.count()) {
118 return false;
119 }
120 QMap<int, QMap<int, QMap<int, QVariant>>>::const_iterator itA = d->dataMap.constBegin();
121 QMap<int, QMap<int, QMap<int, QVariant>>>::const_iterator itB = other->d->dataMap.constBegin();
122 for (; itA != d->dataMap.constEnd(); ++itA, ++itB) {
123 if (itA->count() != itB->count()) {
124 return false;
125 }
126 QMap<int, QMap<int, QVariant>>::const_iterator it2A = itA->constBegin();
127 QMap<int, QMap<int, QVariant>>::const_iterator it2B = itB->constBegin();
128 for (; it2A != itA->constEnd(); ++it2A, ++it2B) {
129 if (it2A->count() != it2B->count()) {
130 return false;
131 }
134 for (; it3A != it2A->constEnd(); ++it3A, ++it3B) {
135 if (it3A.key() != it3B.key()) {
136 return false;
137 }
138 if (!compareAttributes(it3A.key(), it3A.value(), it3B.value())) {
139 return false;
140 }
141 }
142 }
143 }
144 }
145
146 if (!compareHeaderDataMaps(d->horizontalHeaderDataMap, other->d->horizontalHeaderDataMap) || !compareHeaderDataMaps(d->verticalHeaderDataMap, other->d->verticalHeaderDataMap)) {
147 return false;
148 }
149
150 {
151 if (d->modelDataMap.count() != other->d->modelDataMap.count()) {
152 return false;
153 }
154 QMap<int, QVariant>::const_iterator itA = d->modelDataMap.constBegin();
155 QMap<int, QVariant>::const_iterator itB = other->d->modelDataMap.constBegin();
156 for (; itA != d->modelDataMap.constEnd(); ++itA, ++itB) {
157 if (itA.key() != itB.key()) {
158 return false;
159 }
160 if (!compareAttributes(itA.key(), itA.value(), itB.value())) {
161 return false;
162 }
163 }
164 }
165 return true;
166}
167
169 int role, const QVariant &a, const QVariant &b) const
170{
171 if (isKnownAttributesRole(role)) {
172 switch (role) {
175 case DatasetBrushRole:
176 return (a.value<QBrush>() == b.value<QBrush>());
177 case DatasetPenRole:
178 return (a.value<QPen>() == b.value<QPen>());
180 // As of yet there is no ThreeDAttributes class,
181 // and the AbstractThreeDAttributes class is pure virtual,
182 // so we ignore this role for now.
183 // (khz, 04.04.2007)
184 /*
185 return (qVariantValue<ThreeDAttributes>( a ) ==
186 qVariantValue<ThreeDAttributes>( b ));
187 */
188 break;
190 return (a.value<LineAttributes>() == b.value<LineAttributes>());
194 return (a.value<BarAttributes>() == b.value<BarAttributes>());
196 return (a.value<StockBarAttributes>() == b.value<StockBarAttributes>());
200 return (a.value<PieAttributes>() == b.value<PieAttributes>());
205 case DataHiddenRole:
206 return (a.value<bool>() == b.value<bool>());
207 default:
208 Q_ASSERT(false); // all of our own roles need to be handled
209 break;
210 }
211 } else {
212 return (a == b);
213 }
214 return true;
215}
216
218 int role /* = Qt::DisplayRole */) const
219{
220 if (sourceModel()) {
221 const QVariant sourceData = sourceModel()->headerData(section, orientation, role);
222 if (sourceData.isValid()) {
223 return sourceData;
224 }
225 }
226
227 // the source model didn't have data set, let's use our stored values
228 const QMap<int, QMap<int, QVariant>> &map = orientation == Qt::Horizontal ? d->horizontalHeaderDataMap : d->verticalHeaderDataMap;
229 QMap<int, QMap<int, QVariant>>::const_iterator mapIt = map.find(section);
230 if (mapIt != map.constEnd()) {
231 const QMap<int, QVariant> &dataMap = mapIt.value();
233 if (dataMapIt != dataMap.constEnd()) {
234 return dataMapIt.value();
235 }
236 }
237
238 return defaultHeaderData(section, orientation, role);
239}
240
241QVariant AttributesModel::defaultHeaderData(int section, Qt::Orientation orientation, int role) const
242{
243 // Default values if nothing else matches
244
245 const int dataset = section / d->dataDimension;
246
247 switch (role) {
248 case Qt::DisplayRole:
249 // TODO for KDChart 3.0: return QString::number( dataset + 1 );
250 return QString {QLatin1String(orientation == Qt::Vertical ? "Series " : "Item ") + QString::number(dataset)};
252 return d->palette.getBrush(dataset);
254 // if no per model override was set, use the (possibly default) color set for the brush
255 if (!modelData(role).isValid()) {
256 QBrush brush = headerData(section, orientation, DatasetBrushRole).value<QBrush>();
257 return QPen(brush.color());
258 }
259 default:
260 break;
261 }
262
263 return QVariant();
264}
265
267{
268 if (isKnownAttributesRole(role)) {
269 // check if there is something set at global level
270 QVariant v = modelData(role);
271
272 // else return the default setting, if any
273 if (!v.isValid())
274 v = defaultsForRole(role);
275 return v;
276 }
277 return QVariant();
278}
279
280QVariant AttributesModel::data(int column, int role) const
281{
282 if (isKnownAttributesRole(role)) {
283 // check if there is something set for the column (dataset)
284 QVariant v;
285 v = headerData(column, Qt::Horizontal, role);
286
287 // check if there is something set at global level
288 if (!v.isValid())
289 v = data(role); // includes automatic fallback to default
290 return v;
291 }
292 return QVariant();
293}
294
295QVariant AttributesModel::data(const QModelIndex &index, int role) const
296{
297 if (index.isValid()) {
298 Q_ASSERT(index.model() == this);
299 }
300 if (!sourceModel()) {
301 return QVariant();
302 }
303
304 if (index.isValid()) {
305 const QVariant sourceData = sourceModel()->data(mapToSource(index), role);
306 if (sourceData.isValid()) {
307 return sourceData;
308 }
309 }
310
311 // check if we are storing a value for this role at this cell index
312 if (d->dataMap.contains(index.column())) {
314 if (colDataMap.contains(index.row())) {
315 const QMap<int, QVariant> &dataMap = colDataMap[index.row()];
316 if (dataMap.contains(role)) {
317 const QVariant v = dataMap[role];
318 if (v.isValid()) {
319 return v;
320 }
321 }
322 }
323 }
324 // check if there is something set for the column (dataset), or at global level
325 if (index.isValid()) {
326 return data(index.column(), role); // includes automatic fallback to default
327 }
328
329 return QVariant();
330}
331
333{
334 switch (role) {
335 // fallthrough intended
337 case DatasetBrushRole:
338 case DatasetPenRole:
348 case DataHiddenRole:
349 return true;
350 default:
351 return false;
352 }
353}
354
355QVariant AttributesModel::defaultsForRole(int role) const
356{
357 // returns default-constructed QVariant if not found
358 return d->defaultsMap.value(role);
359}
360
361bool AttributesModel::setData(const QModelIndex &index, const QVariant &value, int role)
362{
363 if (!isKnownAttributesRole(role)) {
364 return sourceModel()->setData(mapToSource(index), value, role);
365 } else {
368 dataMap.insert(role, value);
370 return true;
371 }
372}
373
374bool AttributesModel::resetData(const QModelIndex &index, int role)
375{
376 return setData(index, QVariant(), role);
377}
378
380 const QVariant &value, int role)
381{
382 if (sourceModel() && headerData(section, orientation, role) == value) {
383 return true;
384 }
385
386 if (!isKnownAttributesRole(role)) {
387 return sourceModel()->setHeaderData(section, orientation, value, role);
388 } else {
389 QMap<int, QMap<int, QVariant>> &sectionDataMap = orientation == Qt::Horizontal ? d->horizontalHeaderDataMap : d->verticalHeaderDataMap;
390
391 QMap<int, QVariant> &dataMap = sectionDataMap[section];
392 dataMap.insert(role, value);
393 if (sourceModel()) {
396 if (orientation == Qt::Horizontal && numRows > 0)
398 index(numRows - 1, section, QModelIndex()));
399 else if (orientation == Qt::Vertical && numCols > 0)
401 index(section, numCols - 1, QModelIndex()));
402 emit headerDataChanged(orientation, section, section);
403
404 // FIXME: This only makes sense for orientation == Qt::Horizontal,
405 // but what if orientation == Qt::Vertical?
406 if (section != -1 && numRows > 0)
407 emit dataChanged(index(0, section, QModelIndex()),
408 index(numRows - 1, section, QModelIndex()));
409 }
410 return true;
411 }
412}
413
414bool AttributesModel::resetHeaderData(int section, Qt::Orientation orientation, int role)
415{
416 return setHeaderData(section, orientation, QVariant(), role);
417}
418
420{
421 if (d->paletteType == type) {
422 return;
423 }
424 d->paletteType = type;
425 switch (type) {
427 d->palette = Palette::defaultPalette();
428 break;
430 d->palette = Palette::subduedPalette();
431 break;
433 d->palette = Palette::rainbowPalette();
434 break;
435 default:
436 qWarning("Unknown palette type!");
437 }
438}
439
441{
442 return d->paletteType;
443}
444
446{
447 d->modelDataMap.insert(role, value);
448 int numRows = rowCount(QModelIndex());
449 int numCols = columnCount(QModelIndex());
450 if (sourceModel() && numRows > 0 && numCols > 0) {
451 emit attributesChanged(index(0, 0, QModelIndex()),
452 index(numRows - 1, numCols - 1, QModelIndex()));
453 beginResetModel();
454 endResetModel();
455 }
456 return true;
457}
458
460{
461 return d->modelDataMap.value(role, QVariant());
462}
463
465{
466 if (sourceModel()) {
467 return sourceModel()->rowCount(mapToSource(index));
468 } else {
469 return 0;
470 }
471}
472
474{
475 if (sourceModel()) {
476 return sourceModel()->columnCount(mapToSource(index));
477 } else {
478 return 0;
479 }
480}
481
483{
484 if (this->sourceModel() != nullptr) {
486 this, SLOT(slotDataChanged(const QModelIndex &, const QModelIndex &)));
487 disconnect(this->sourceModel(), SIGNAL(rowsInserted(const QModelIndex &, int, int)),
488 this, SLOT(slotRowsInserted(const QModelIndex &, int, int)));
489 disconnect(this->sourceModel(), SIGNAL(rowsRemoved(const QModelIndex &, int, int)),
490 this, SLOT(slotRowsRemoved(const QModelIndex &, int, int)));
492 this, SLOT(slotRowsAboutToBeInserted(const QModelIndex &, int, int)));
493 disconnect(this->sourceModel(), SIGNAL(rowsAboutToBeRemoved(const QModelIndex &, int, int)),
494 this, SLOT(slotRowsAboutToBeRemoved(const QModelIndex &, int, int)));
495 disconnect(this->sourceModel(), SIGNAL(columnsInserted(const QModelIndex &, int, int)),
496 this, SLOT(slotColumnsInserted(const QModelIndex &, int, int)));
497 disconnect(this->sourceModel(), SIGNAL(columnsRemoved(const QModelIndex &, int, int)),
498 this, SLOT(slotColumnsRemoved(const QModelIndex &, int, int)));
500 this, SLOT(slotColumnsAboutToBeInserted(const QModelIndex &, int, int)));
502 this, SLOT(slotColumnsAboutToBeRemoved(const QModelIndex &, int, int)));
504 this, SIGNAL(modelReset()));
506 this, SIGNAL(layoutChanged()));
507 }
509 if (this->sourceModel() != nullptr) {
510 connect(this->sourceModel(), SIGNAL(dataChanged(const QModelIndex &, const QModelIndex &)),
511 this, SLOT(slotDataChanged(const QModelIndex &, const QModelIndex &)));
512 connect(this->sourceModel(), SIGNAL(rowsInserted(const QModelIndex &, int, int)),
513 this, SLOT(slotRowsInserted(const QModelIndex &, int, int)));
514 connect(this->sourceModel(), SIGNAL(rowsRemoved(const QModelIndex &, int, int)),
515 this, SLOT(slotRowsRemoved(const QModelIndex &, int, int)));
516 connect(this->sourceModel(), SIGNAL(rowsAboutToBeInserted(const QModelIndex &, int, int)),
517 this, SLOT(slotRowsAboutToBeInserted(const QModelIndex &, int, int)));
518 connect(this->sourceModel(), SIGNAL(rowsAboutToBeRemoved(const QModelIndex &, int, int)),
519 this, SLOT(slotRowsAboutToBeRemoved(const QModelIndex &, int, int)));
520 connect(this->sourceModel(), SIGNAL(columnsInserted(const QModelIndex &, int, int)),
521 this, SLOT(slotColumnsInserted(const QModelIndex &, int, int)));
522 connect(this->sourceModel(), SIGNAL(columnsRemoved(const QModelIndex &, int, int)),
523 this, SLOT(slotColumnsRemoved(const QModelIndex &, int, int)));
525 this, SLOT(slotColumnsAboutToBeInserted(const QModelIndex &, int, int)));
526 connect(this->sourceModel(), SIGNAL(columnsAboutToBeRemoved(const QModelIndex &, int, int)),
527 this, SLOT(slotColumnsAboutToBeRemoved(const QModelIndex &, int, int)));
529 this, SIGNAL(modelReset()));
531 this, SIGNAL(layoutChanged()));
532 }
533}
534
535void AttributesModel::slotRowsAboutToBeInserted(const QModelIndex &parent, int start, int end)
536{
538}
539
540void AttributesModel::slotColumnsAboutToBeInserted(const QModelIndex &parent, int start, int end)
541{
543}
544
545void AttributesModel::slotRowsInserted(const QModelIndex &parent, int start, int end)
546{
548 Q_UNUSED(start);
549 Q_UNUSED(end);
551}
552
553void AttributesModel::slotColumnsInserted(const QModelIndex &parent, int start, int end)
554{
556 Q_UNUSED(start);
557 Q_UNUSED(end);
559}
560
561void AttributesModel::slotRowsAboutToBeRemoved(const QModelIndex &parent, int start, int end)
562{
564}
565
566void AttributesModel::slotColumnsAboutToBeRemoved(const QModelIndex &parent, int start, int end)
567{
569}
570
571void AttributesModel::slotRowsRemoved(const QModelIndex &parent, int start, int end)
572{
574 Q_UNUSED(start);
575 Q_UNUSED(end);
577}
578
579void AttributesModel::removeEntriesFromDataMap(int start, int end)
580{
581 QMap<int, QMap<int, QMap<int, QVariant>>>::iterator it = d->dataMap.find(end);
582 // check that the element was found
583 if (it != d->dataMap.end()) {
584 ++it;
586 for (int i = start; i < end && it != d->dataMap.end(); ++i) {
587 d->dataMap[i] = it.value();
588 indexesToDel << it.key();
589 ++it;
590 }
591 if (indexesToDel.isEmpty()) {
592 for (int i = start; i < end; ++i) {
593 indexesToDel << i;
594 }
595 }
596 for (int i = 0; i < indexesToDel.count(); ++i) {
597 d->dataMap.remove(indexesToDel[i]);
598 }
599 }
600}
601
602void AttributesModel::removeEntriesFromDirectionDataMaps(Qt::Orientation dir, int start, int end)
603{
604 QMap<int, QMap<int, QVariant>> &sectionDataMap = dir == Qt::Horizontal ? d->horizontalHeaderDataMap : d->verticalHeaderDataMap;
606 // check that the element was found
607 if (it != sectionDataMap.end()) {
609 for (int i = start; i < end && it != sectionDataMap.end(); ++i) {
611 indexesToDel << it.key();
612 ++it;
613 }
614 if (indexesToDel.isEmpty()) {
615 for (int i = start; i < end; ++i) {
616 indexesToDel << i;
617 }
618 }
619 for (int i = 0; i < indexesToDel.count(); ++i) {
621 }
622 }
623}
624
625void AttributesModel::slotColumnsRemoved(const QModelIndex &parent, int start, int end)
626{
628 Q_UNUSED(start);
629 Q_UNUSED(end);
630 Q_ASSERT_X(sourceModel(), "removeColumn", "This should only be triggered if a valid source Model exists!");
631 for (int i = start; i <= end; ++i) {
632 d->verticalHeaderDataMap.remove(start);
633 }
634 removeEntriesFromDataMap(start, end);
635 removeEntriesFromDirectionDataMaps(Qt::Horizontal, start, end);
636 removeEntriesFromDirectionDataMaps(Qt::Vertical, start, end);
637
639}
640
641void AttributesModel::slotDataChanged(const QModelIndex &topLeft, const QModelIndex &bottomRight)
642{
643 emit dataChanged(mapFromSource(topLeft), mapFromSource(bottomRight));
644}
645
647{
648 if (value.isValid()) {
649 d->defaultsMap.insert(role, value);
650 } else {
651 // erase the possibly existing value to not let the map grow:
652 QMap<int, QVariant>::iterator it = d->defaultsMap.find(role);
653 if (it != d->defaultsMap.end()) {
654 d->defaultsMap.erase(it);
655 }
656 }
657
659}
660
662{
663 // ### need to "reformat" or throw away internal data?
664 d->dataDimension = dimension;
665}
666
668{
669 return d->dataDimension;
670}
Declaring the class KDChart::DataValueAttributes.
Contains KDChart macros.
Base class for all proxy models used inside KD Chart.
QModelIndex index(int row, int col, const QModelIndex &index) const override
Reimplemented for internal purposes.
QModelIndex mapToSource(const QModelIndex &proxyIndex) const override
Reimplemented for internal purposes.
QModelIndex mapFromSource(const QModelIndex &sourceIndex) const override
Reimplemented for internal purposes.
A proxy model used for decorating data with attributes.
virtual QVariant defaultHeaderData(int section, Qt::Orientation orientation, int role=Qt::DisplayRole) const
void attributesChanged(const QModelIndex &, const QModelIndex &)
AttributesModel(QAbstractItemModel *model, QObject *parent=nullptr)
QVariant data(int role) const
int rowCount(const QModelIndex &) const override
bool compareAttributes(int role, const QVariant &a, const QVariant &b) const
void setDatasetDimension(int dimension)
bool resetHeaderData(int section, Qt::Orientation orientation, int role=Qt::DisplayRole)
bool setHeaderData(int section, Qt::Orientation orientation, const QVariant &value, int role=Qt::DisplayRole) override
QVariant modelData(int role) const
void setPaletteType(PaletteType type)
void setSourceModel(QAbstractItemModel *sourceModel) override
bool resetData(const QModelIndex &index, int role=Qt::DisplayRole)
void setDefaultForRole(int role, const QVariant &value)
void initFrom(const AttributesModel *other)
bool compare(const AttributesModel *other) const
bool setData(const QModelIndex &index, const QVariant &value, int role=Qt::DisplayRole) override
bool isKnownAttributesRole(int role) const
QVariant headerData(int section, Qt::Orientation orientation, int role=Qt::DisplayRole) const override
int columnCount(const QModelIndex &) const override
bool setModelData(const QVariant value, int role)
Set of attributes for changing the appearance of bar charts.
Diagram attributes dealing with data value labels.
static const QVariant & defaultAttributesAsVariant()
Set of attributes for changing the appearance of line charts.
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()
A set of attributes controlling the appearance of pie charts.
Attributes to customize the appearance of a column in a stock chart.
Cell-specific attributes regarding value tracking.
@ DataValueLabelAttributesRole
@ LineAttributesRole
@ ThreeDLineAttributesRole
@ ThreeDBarAttributesRole
@ ThreeDPieAttributesRole
@ ThreeDAttributesRole
@ StockBarAttributesRole
@ PieAttributesRole
@ BarAttributesRole
@ ValueTrackerAttributesRole
void beginInsertColumns(const QModelIndex &parent, int first, int last)
void beginInsertRows(const QModelIndex &parent, int first, int last)
void beginRemoveColumns(const QModelIndex &parent, int first, int last)
void beginRemoveRows(const QModelIndex &parent, int first, int last)
void columnsAboutToBeInserted(const QModelIndex &parent, int first, int last)
void columnsAboutToBeRemoved(const QModelIndex &parent, int first, int last)
void columnsInserted(const QModelIndex &parent, int first, int last)
void columnsRemoved(const QModelIndex &parent, int first, int last)
void dataChanged(const QModelIndex &topLeft, const QModelIndex &bottomRight, const QVector< int > &roles)
void headerDataChanged(Qt::Orientation orientation, int first, int last)
void layoutChanged(const QList< QPersistentModelIndex > &parents, QAbstractItemModel::LayoutChangeHint hint)
void rowsAboutToBeInserted(const QModelIndex &parent, int start, int end)
void rowsAboutToBeRemoved(const QModelIndex &parent, int first, int last)
void rowsInserted(const QModelIndex &parent, int first, int last)
void rowsRemoved(const QModelIndex &parent, int first, int last)
virtual void setSourceModel(QAbstractItemModel *sourceModel)
const QColor & color() const const
T & value() const const
QMap::const_iterator constBegin() const const
QMap::const_iterator constEnd() const const
bool contains(const Key &key) const const
QMap::iterator find(const Key &key)
QMap::iterator insert(const Key &key, const T &value)
QMap::iterator upperBound(const Key &key)
const T value(const Key &key, const T &defaultValue) const const
int column() const const
bool isValid() const const
const QAbstractItemModel * model() const const
int row() const const
QMetaObject::Connection connect(const QObject *sender, const char *signal, const QObject *receiver, const char *method, Qt::ConnectionType type)
bool disconnect(const QObject *sender, const char *signal, const QObject *receiver, const char *method)
QObject * parent() const const
T qobject_cast(QObject *object)
QString number(int n, int base)
DisplayRole
Orientation
bool isValid() const const
T value() const const
T value(int i) const const

© 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 on Fri Feb 23 2024 00:02:58 for KD Chart API Documentation by doxygen 1.9.8