1// Copyright (C) 2024 The Qt Company Ltd.
2// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only
3#include <QtCore/qabstractitemmodel.h>
4#include <QtGraphs/qpiemodelmapper.h>
5#include <QtGraphs/qpieseries.h>
6#include <private/qpiemodelmapper_p.h>
7
8QT_BEGIN_NAMESPACE
9
10/*!
11 \class QPieModelMapper
12 \inmodule QtGraphs
13 \ingroup graphs_2D
14 \brief The QPieModelMapper is a model mapper for pie series.
15
16 Model mappers enable using a data model derived from the QAbstractItemModel
17 class as a data source for a graph. A model mapper is used to create
18 a connection between a data model and QPieSeries.
19
20 Both model and pie series properties can be used to manipulate the data. The
21 model mapper keeps the pie series and the data model in sync.
22*/
23/*!
24 \qmltype PieModelMapper
25 \nativetype QPieModelMapper
26 \inqmlmodule QtGraphs
27 \ingroup graphs_qml_2D
28
29 \brief Model mapper for pie series.
30
31 Model mappers enable using a data model derived from the QAbstractItemModel
32 class as a data source for a graph. A model mapper is used to create
33 a connection between a data model and PieSeries.
34
35 Both model and pie series properties can be used to manipulate the data. The
36 model mapper keeps the pie series and the data model in sync.
37
38 The following QML example creates a pie series with four slices (assuming
39 the model has at least five rows). Each slice gets a label from column 1 and
40 a value from column 2.
41 \code
42 PieModelMapper {
43 series: pieSeries
44 model: customModel
45 labelsSection: 1
46 valuesSection: 2
47 firstRow: 1
48 rowCount: 4
49 orientation: Qt.Vertical
50 }
51 \endcode
52*/
53
54/*!
55 \property QPieModelMapper::series
56 \brief The pie series that is used by the mapper.
57
58 All the data in the series is discarded when it is set to the mapper.
59 When a new series is specified, the old series is disconnected (but it preserves its data).
60*/
61/*!
62 \qmlproperty PieSeries PieModelMapper::series
63 The pie series that is used by the mapper. If you define the mapper element as a child for a
64 PieSeries, leave this property undefined. All the data in the series is discarded when it is set to the mapper.
65 When new series is specified the old series is disconnected (but it preserves its data).
66*/
67
68/*!
69 \property QPieModelMapper::model
70 \brief The model that is used by the mapper.
71*/
72/*!
73 \qmlproperty model PieModelMapper::model
74 The QAbstractItemModel based model that is used by the mapper. You need to implement the model
75 and expose it to QML.
76
77 \note The model has to support adding and removing rows or columns and modifying
78 the data in the cells.
79*/
80
81/*!
82 \property QPieModelMapper::valuesSection
83 \brief The column or row of the model that is kept in sync with the values of the pie's slices.
84
85 The default value is -1 (invalid mapping).
86
87 \sa QPieModelMapper::orientation
88*/
89/*!
90 \qmlproperty qsizetype PieModelMapper::valuesSection
91 The column or row of the model that is kept in sync with the values of the pie's slices.
92 The default value is -1 (invalid mapping).
93
94 \sa orientation
95*/
96
97/*!
98 \property QPieModelMapper::labelsSection
99 \brief The column or row of the model that is kept in sync with the labels of the pie's slices.
100
101 The default value is -1 (invalid mapping).
102
103 \sa QPieModelMapper::orientation
104*/
105/*!
106 \qmlproperty qsizetype PieModelMapper::labelsSection
107 The column or row of the model that is kept in sync with the labels of the pie's slices.
108 The default value is -1 (invalid mapping).
109
110 \sa orientation
111*/
112
113/*!
114 \property QPieModelMapper::first
115 \brief The column or row of the model that contains the first slice value.
116
117 The minimum and default value is 0.
118
119 \sa QPieModelMapper::orientation
120*/
121/*!
122 \qmlproperty qsizetype PieModelMapper::first
123 The column or row of the model that contains the first slice value.
124 The default value is 0.
125
126 \sa orientation
127*/
128
129/*!
130 \property QPieModelMapper::count
131 \brief The number of columns or rows of the model that are mapped as the data for a pie series.
132
133 The minimum and default value is -1 (number limited by the number of rows in the model).
134
135 \sa QPieModelMapper::orientation
136*/
137/*!
138 \qmlproperty qsizetype PieModelMapper::count
139 The number of columns or rows of the model that are mapped as the data for a pie series.
140 The default value is -1 (number limited by the number of rows in the model).
141
142 \sa orientation
143*/
144
145/*!
146 \property QPieModelMapper::orientation
147 \brief Tells the modelmapper how to map data from a model. If
148 \c{Qt::Vertical} is used, each of the model's rows defines a pie slice, and the
149 model's columns define the label or the value of the pie slice. When the orientation is set to
150 \c{Qt::Horizontal}, each of the model's columns defines a pie slice, and the model's
151 rows define the label or the value of the pie slice.
152
153 The default value is \c{Qt::Vertical}
154*/
155/*!
156 \qmlproperty orientation PieModelMapper::orientation
157 Tells the modelmapper how to map data from a model. If
158 \c{Qt.Vertical} is used, each of the model's rows defines a pie slice, and the
159 model's columns define the label or the value of the pie slice. When the orientation is set to
160 \c{Qt.Horizontal}, each of the model's columns defines a pie slice, and the model's
161 rows define the label or the value of the pie slice.
162
163 The default value is \c{Qt.Vertical}
164*/
165
166/*!
167 \qmlsignal PieModelMapper::seriesChanged()
168
169 This signal is emitted when the series that the mapper is connected to changes.
170*/
171
172/*!
173 \qmlsignal PieModelMapper::modelChanged()
174
175 This signal is emitted when the model that the mapper is connected to changes.
176*/
177
178/*!
179 \qmlsignal PieModelMapper::valuesSectionChanged()
180
181 This signal is emitted when the values section changes.
182*/
183
184/*!
185 \qmlsignal PieModelMapper::labelsSectionChanged()
186
187 This signal is emitted when the labels section changes.
188*/
189
190/*!
191 \qmlsignal PieModelMapper::firstChanged()
192 This signal is emitted when the first slice changes.
193*/
194
195/*!
196 \qmlsignal PieModelMapper::countChanged()
197 This signal is emitted when the count changes.
198*/
199
200/*!
201 \qmlsignal PieModelMapper::orientationChanged()
202 This signal is emitted when the orientation changes.
203*/
204
205QPieModelMapper::~QPieModelMapper() {}
206
207QPieModelMapper::QPieModelMapper(QObject *parent)
208 : QObject{*(new QPieModelMapperPrivate), parent} {}
209
210QPieModelMapper::QPieModelMapper(QPieModelMapperPrivate &dd, QObject *parent)
211 : QObject(dd, parent) {}
212
213void QPieModelMapper::onSliceLabelChanged() {
214 Q_D(QPieModelMapper);
215 d->onSliceLabelChanged(slice: qobject_cast<QPieSlice *>(object: sender()));
216}
217
218void QPieModelMapper::onSliceValueChanged() {
219 Q_D(QPieModelMapper);
220 d->onSliceValueChanged(slice: qobject_cast<QPieSlice *>(object: sender()));
221}
222
223QAbstractItemModel *QPieModelMapper::model() const {
224 Q_D(const QPieModelMapper);
225 return d->m_model;
226}
227
228void QPieModelMapper::setModel(QAbstractItemModel *model) {
229 if (model == nullptr)
230 return;
231 Q_D(QPieModelMapper);
232 if (d->m_model) {
233 QObjectPrivate::disconnect(sender: d->m_model,
234 signal: &QAbstractItemModel::modelReset,
235 receiverPrivate: d,
236 slot: &QPieModelMapperPrivate::initializePieFromModel);
237 QObjectPrivate::disconnect(sender: d->m_model,
238 signal: &QAbstractItemModel::dataChanged,
239 receiverPrivate: d,
240 slot: &QPieModelMapperPrivate::onModelUpdated);
241 QObjectPrivate::disconnect(sender: d->m_model,
242 signal: &QAbstractItemModel::rowsInserted,
243 receiverPrivate: d,
244 slot: &QPieModelMapperPrivate::onModelRowsAdded);
245 QObjectPrivate::disconnect(sender: d->m_model,
246 signal: &QAbstractItemModel::rowsRemoved,
247 receiverPrivate: d,
248 slot: &QPieModelMapperPrivate::onModelRowsRemoved);
249 QObjectPrivate::disconnect(sender: d->m_model,
250 signal: &QAbstractItemModel::columnsInserted,
251 receiverPrivate: d,
252 slot: &QPieModelMapperPrivate::onModelColumnsAdded);
253 QObjectPrivate::disconnect(sender: d->m_model,
254 signal: &QAbstractItemModel::columnsRemoved,
255 receiverPrivate: d,
256 slot: &QPieModelMapperPrivate::onModelColumnsRemoved);
257 QObjectPrivate::disconnect(sender: d->m_model,
258 signal: &QAbstractItemModel::destroyed,
259 receiverPrivate: d,
260 slot: &QPieModelMapperPrivate::handleModelDestroyed);
261 }
262 d->m_model = model;
263 d->initializePieFromModel();
264
265 QObjectPrivate::connect(sender: d->m_model,
266 signal: &QAbstractItemModel::modelReset,
267 receiverPrivate: d,
268 slot: &QPieModelMapperPrivate::initializePieFromModel);
269 QObjectPrivate::connect(sender: d->m_model,
270 signal: &QAbstractItemModel::dataChanged,
271 receiverPrivate: d,
272 slot: &QPieModelMapperPrivate::onModelUpdated);
273 QObjectPrivate::connect(sender: d->m_model,
274 signal: &QAbstractItemModel::rowsInserted,
275 receiverPrivate: d,
276 slot: &QPieModelMapperPrivate::onModelRowsAdded);
277 QObjectPrivate::connect(sender: d->m_model,
278 signal: &QAbstractItemModel::rowsRemoved,
279 receiverPrivate: d,
280 slot: &QPieModelMapperPrivate::onModelRowsRemoved);
281 QObjectPrivate::connect(sender: d->m_model,
282 signal: &QAbstractItemModel::columnsInserted,
283 receiverPrivate: d,
284 slot: &QPieModelMapperPrivate::onModelColumnsAdded);
285 QObjectPrivate::connect(sender: d->m_model,
286 signal: &QAbstractItemModel::columnsRemoved,
287 receiverPrivate: d,
288 slot: &QPieModelMapperPrivate::onModelColumnsRemoved);
289 QObjectPrivate::connect(sender: d->m_model,
290 signal: &QAbstractItemModel::destroyed,
291 receiverPrivate: d,
292 slot: &QPieModelMapperPrivate::handleModelDestroyed);
293 Q_EMIT modelChanged();
294}
295
296QPieSeries *QPieModelMapper::series() const {
297 Q_D(const QPieModelMapper);
298 return d->m_series;
299}
300
301void QPieModelMapper::setSeries(QPieSeries *series) {
302 Q_D(QPieModelMapper);
303 if (d->m_series) {
304 QObjectPrivate::disconnect(sender: d->m_series,
305 signal: &QPieSeries::added,
306 receiverPrivate: d,
307 slot: &QPieModelMapperPrivate::onSlicesAdded);
308 QObjectPrivate::disconnect(sender: d->m_series,
309 signal: &QPieSeries::removed,
310 receiverPrivate: d,
311 slot: &QPieModelMapperPrivate::onSlicesRemoved);
312 QObjectPrivate::disconnect(sender: d->m_series,
313 signal: &QPieSeries::destroyed,
314 receiverPrivate: d,
315 slot: &QPieModelMapperPrivate::handleSeriesDestroyed);
316 }
317
318 if (series == 0)
319 return;
320
321 d->m_series = series;
322 d->initializePieFromModel();
323 // connect the signals from the series
324 QObjectPrivate::connect(sender: d->m_series,
325 signal: &QPieSeries::added,
326 receiverPrivate: d,
327 slot: &QPieModelMapperPrivate::onSlicesAdded);
328 QObjectPrivate::connect(sender: d->m_series,
329 signal: &QPieSeries::removed,
330 receiverPrivate: d,
331 slot: &QPieModelMapperPrivate::onSlicesRemoved);
332 QObjectPrivate::connect(sender: d->m_series,
333 signal: &QPieSeries::destroyed,
334 receiverPrivate: d,
335 slot: &QPieModelMapperPrivate::handleSeriesDestroyed);
336 Q_EMIT seriesChanged();
337}
338
339qsizetype QPieModelMapper::first() const
340{
341 Q_D(const QPieModelMapper);
342 return d->m_first;
343}
344
345void QPieModelMapper::setFirst(qsizetype first)
346{
347 Q_D(QPieModelMapper);
348 d->m_first = qMax(a: first, b: 0);
349 d->initializePieFromModel();
350 Q_EMIT firstChanged();
351}
352
353qsizetype QPieModelMapper::count() const
354{
355 Q_D(const QPieModelMapper);
356 return d->m_count;
357}
358
359void QPieModelMapper::setCount(qsizetype count)
360{
361 Q_D(QPieModelMapper);
362 d->m_count = qMax(a: count, b: -1);
363 d->initializePieFromModel();
364 Q_EMIT countChanged();
365}
366
367Qt::Orientation QPieModelMapper::orientation() const {
368 Q_D(const QPieModelMapper);
369 return d->m_orientation;
370}
371
372void QPieModelMapper::setOrientation(Qt::Orientation orientation) {
373 Q_D(QPieModelMapper);
374 d->m_orientation = orientation;
375 d->initializePieFromModel();
376 Q_EMIT orientationChanged();
377}
378
379qsizetype QPieModelMapper::valuesSection() const
380{
381 Q_D(const QPieModelMapper);
382 return d->m_valuesSection;
383}
384
385void QPieModelMapper::setValuesSection(qsizetype valuesSection)
386{
387 Q_D(QPieModelMapper);
388 d->m_valuesSection = qMax(a: -1, b: valuesSection);
389 d->initializePieFromModel();
390 Q_EMIT valuesSectionChanged();
391}
392
393qsizetype QPieModelMapper::labelsSection() const
394{
395 Q_D(const QPieModelMapper);
396 return d->m_labelsSection;
397}
398
399void QPieModelMapper::setLabelsSection(qsizetype labelsSection)
400{
401 Q_D(QPieModelMapper);
402 d->m_labelsSection = qMax(a: -1, b: labelsSection);
403 d->initializePieFromModel();
404 Q_EMIT labelsSectionChanged();
405}
406
407///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
408
409QPieModelMapperPrivate::QPieModelMapperPrivate() {}
410
411QPieModelMapperPrivate::~QPieModelMapperPrivate() {}
412
413void QPieModelMapperPrivate::blockModelSignals(bool block) {
414 m_modelSignalsBlock = block;
415}
416
417void QPieModelMapperPrivate::blockSeriesSignals(bool block) {
418 m_seriesSignalsBlock = block;
419}
420
421QPieSlice *QPieModelMapperPrivate::pieSlice(QModelIndex index) const {
422 if (!index.isValid())
423 return 0; // index is invalid
424
425 if (m_orientation == Qt::Vertical
426 && (index.column() == m_valuesSection || index.column() == m_labelsSection)) {
427 if (index.row() >= m_first && (m_count == -1 || index.row() < m_first + m_count)) {
428 if (m_model->index(row: index.row(), column: m_valuesSection).isValid()
429 && m_model->index(row: index.row(), column: m_labelsSection).isValid())
430 return m_series->slices().at(i: index.row() - m_first);
431 else
432 return 0;
433 }
434 } else if (m_orientation == Qt::Horizontal
435 && (index.row() == m_valuesSection || index.row() == m_labelsSection)) {
436 if (index.column() >= m_first && (m_count == -1 || index.column() < m_first + m_count)) {
437 if (m_model->index(row: m_valuesSection, column: index.column()).isValid()
438 && m_model->index(row: m_labelsSection, column: index.column()).isValid())
439 return m_series->slices().at(i: index.column() - m_first);
440 else
441 return 0;
442 }
443 }
444 return 0; // This part of model has not been mapped to any slice
445}
446
447QModelIndex QPieModelMapperPrivate::valueModelIndex(qsizetype sliceIndex) {
448 if (m_count != -1 && sliceIndex >= m_count)
449 return QModelIndex(); // invalid
450
451 if (m_orientation == Qt::Vertical)
452 return m_model->index(row: int(sliceIndex) + m_first, column: m_valuesSection);
453 else
454 return m_model->index(row: m_valuesSection, column: int(sliceIndex) + m_first);
455}
456
457QModelIndex QPieModelMapperPrivate::labelModelIndex(qsizetype sliceIndex) {
458 if (m_count != -1 && sliceIndex >= m_count)
459 return QModelIndex(); // invalid
460
461 if (m_orientation == Qt::Vertical)
462 return m_model->index(row: int(sliceIndex) + m_first, column: m_labelsSection);
463 else
464 return m_model->index(row: m_labelsSection, column: int(sliceIndex) + m_first);
465}
466
467bool QPieModelMapperPrivate::isLabelIndex(QModelIndex index) const {
468 if (m_orientation == Qt::Vertical && index.column() == m_labelsSection)
469 return true;
470 else if (m_orientation == Qt::Horizontal && index.row() == m_labelsSection)
471 return true;
472
473 return false;
474}
475
476bool QPieModelMapperPrivate::isValueIndex(QModelIndex index) const {
477 if (m_orientation == Qt::Vertical && index.column() == m_valuesSection)
478 return true;
479 else if (m_orientation == Qt::Horizontal && index.row() == m_valuesSection)
480 return true;
481
482 return false;
483}
484
485void QPieModelMapperPrivate::onSlicesAdded(const QList<QPieSlice *> &slices) {
486 if (m_seriesSignalsBlock)
487 return;
488
489 if (slices.size() == 0)
490 return;
491
492 int firstIndex = int(m_series->slices().indexOf(t: slices.at(i: 0)));
493 if (firstIndex == -1)
494 return;
495
496 if (m_count != -1)
497 m_count += slices.size();
498 Q_Q(QPieModelMapper);
499 for (int i = firstIndex; i < firstIndex + slices.size(); i++) {
500 m_slices.insert(i, t: slices.at(i: i - firstIndex));
501 QObject::connect(sender: slices.at(i: i - firstIndex),
502 signal: &QPieSlice::labelChanged,
503 context: q,
504 slot: &QPieModelMapper::onSliceLabelChanged);
505 QObject::connect(sender: slices.at(i: i - firstIndex),
506 signal: &QPieSlice::valueChanged,
507 context: q,
508 slot: &QPieModelMapper::onSliceValueChanged);
509 }
510
511 blockModelSignals();
512 if (m_orientation == Qt::Vertical)
513 m_model->insertRows(row: firstIndex + m_first, count: int(slices.size()));
514 else
515 m_model->insertColumns(column: firstIndex + m_first, count: int(slices.size()));
516
517 for (int i = firstIndex; i < firstIndex + slices.size(); i++) {
518 m_model->setData(index: valueModelIndex(sliceIndex: i), value: slices.at(i: i - firstIndex)->value());
519 m_model->setData(index: labelModelIndex(sliceIndex: i), value: slices.at(i: i - firstIndex)->label());
520 }
521 blockModelSignals(block: false);
522}
523
524void QPieModelMapperPrivate::onSlicesRemoved(const QList<QPieSlice *> &slices) {
525 if (m_seriesSignalsBlock)
526 return;
527
528 if (slices.size() == 0)
529 return;
530
531 int firstIndex = int(m_slices.indexOf(t: slices.at(i: 0)));
532 if (firstIndex == -1)
533 return;
534
535 if (m_count != -1)
536 m_count -= slices.size();
537
538 for (int i = firstIndex + int(slices.size()) - 1; i >= firstIndex; i--)
539 m_slices.removeAt(i);
540
541 blockModelSignals();
542 if (m_orientation == Qt::Vertical)
543 m_model->removeRows(row: firstIndex + m_first, count: int(slices.size()));
544 else
545 m_model->removeColumns(column: firstIndex + m_first, count: int(slices.size()));
546 blockModelSignals(block: false);
547}
548
549void QPieModelMapperPrivate::onSliceLabelChanged(const QPieSlice *slice) {
550 if (m_seriesSignalsBlock)
551 return;
552
553 blockModelSignals();
554 m_model->setData(index: labelModelIndex(sliceIndex: m_series->slices().indexOf(t: slice)), value: slice->label());
555 blockModelSignals(block: false);
556}
557
558void QPieModelMapperPrivate::onSliceValueChanged(const QPieSlice *slice) {
559 if (m_seriesSignalsBlock)
560 return;
561
562 blockModelSignals();
563 m_model->setData(index: valueModelIndex(sliceIndex: m_series->slices().indexOf(t: slice)), value: slice->value());
564 blockModelSignals(block: false);
565}
566
567void QPieModelMapperPrivate::handleSeriesDestroyed() { m_series = nullptr; }
568
569void QPieModelMapperPrivate::onModelUpdated(QModelIndex topLeft, QModelIndex bottomRight)
570{
571 if (m_model == nullptr || m_series == nullptr)
572 return;
573
574 if (m_modelSignalsBlock)
575 return;
576
577 blockSeriesSignals();
578 QModelIndex index;
579 QPieSlice *slice;
580 for (int row = topLeft.row(); row <= bottomRight.row(); row++) {
581 for (int column = topLeft.column(); column <= bottomRight.column(); column++) {
582 index = topLeft.sibling(arow: row, acolumn: column);
583 slice = pieSlice(index);
584 if (slice) {
585 if (isValueIndex(index))
586 slice->setValue(m_model->data(index, role: Qt::DisplayRole).toReal());
587 if (isLabelIndex(index))
588 slice->setLabel(m_model->data(index, role: Qt::DisplayRole).toString());
589 }
590 }
591 }
592 blockSeriesSignals(block: false);
593}
594
595void QPieModelMapperPrivate::onModelRowsAdded(QModelIndex parent, qsizetype start, qsizetype end)
596{
597 Q_UNUSED(parent);
598 if (m_modelSignalsBlock)
599 return;
600
601 blockSeriesSignals();
602 if (m_orientation == Qt::Vertical) {
603 insertData(start, end);
604 } else if (start <= m_valuesSection
605 || start <= m_labelsSection) { // if the changes affect the map - reinitialize the pie
606 initializePieFromModel();
607 }
608 blockSeriesSignals(block: false);
609}
610
611void QPieModelMapperPrivate::onModelRowsRemoved(QModelIndex parent, qsizetype start, qsizetype end)
612{
613 Q_UNUSED(parent);
614 if (m_modelSignalsBlock)
615 return;
616
617 blockSeriesSignals();
618 if (m_orientation == Qt::Vertical) {
619 removeData(start, end);
620 } else if (start <= m_valuesSection || start <= m_labelsSection) {
621 // if the changes affect the map - reinitialize the pie
622 initializePieFromModel();
623 }
624 blockSeriesSignals(block: false);
625}
626
627void QPieModelMapperPrivate::onModelColumnsAdded(QModelIndex parent, qsizetype start, qsizetype end)
628{
629 Q_UNUSED(parent);
630 if (m_modelSignalsBlock)
631 return;
632
633 blockSeriesSignals();
634 if (m_orientation == Qt::Horizontal) {
635 insertData(start, end);
636 } else if (start <= m_valuesSection || start <= m_labelsSection) {
637 // if the changes affect the map - reinitialize the pie
638 initializePieFromModel();
639 }
640 blockSeriesSignals(block: false);
641}
642
643void QPieModelMapperPrivate::onModelColumnsRemoved(QModelIndex parent, qsizetype start, qsizetype end)
644{
645 Q_UNUSED(parent);
646 if (m_modelSignalsBlock)
647 return;
648
649 blockSeriesSignals();
650 if (m_orientation == Qt::Horizontal) {
651 removeData(start, end);
652 } else if (start <= m_valuesSection || start <= m_labelsSection) {
653 // if the changes affect the map - reinitialize the pie
654 initializePieFromModel();
655 }
656 blockSeriesSignals(block: false);
657}
658
659void QPieModelMapperPrivate::handleModelDestroyed() { m_model = nullptr; }
660
661void QPieModelMapperPrivate::insertData(qsizetype start, qsizetype end) {
662 if (m_model == nullptr || m_series == nullptr)
663 return;
664
665 if (m_count != -1 && start >= m_first + m_count) {
666 return;
667 } else {
668 qsizetype addedCount = end - start + 1;
669 if (m_count != -1 && addedCount > m_count)
670 addedCount = m_count;
671 qsizetype first = qMax(a: start, b: m_first);
672 qsizetype last = qMin(a: first + addedCount - 1,
673 b: m_orientation == Qt::Vertical ? m_model->rowCount() - 1
674 : m_model->columnCount() - 1);
675 Q_Q(QPieModelMapper);
676
677 for (qsizetype i = first; i <= last; i++) {
678 QModelIndex valueIndex = valueModelIndex(sliceIndex: i - m_first);
679 QModelIndex labelIndex = labelModelIndex(sliceIndex: i - m_first);
680 if (valueIndex.isValid() && labelIndex.isValid()) {
681 QPieSlice *slice = new QPieSlice;
682 slice->setValue(m_model->data(index: valueIndex, role: Qt::DisplayRole).toDouble());
683 slice->setLabel(m_model->data(index: labelIndex, role: Qt::DisplayRole).toString());
684 QObject::connect(sender: slice,
685 signal: &QPieSlice::labelChanged,
686 context: q,
687 slot: &QPieModelMapper::onSliceLabelChanged);
688 QObject::connect(sender: slice,
689 signal: &QPieSlice::valueChanged,
690 context: q,
691 slot: &QPieModelMapper::onSliceValueChanged);
692 m_series->insert(index: i - m_first, slice);
693 m_slices.insert(i: i - m_first, t: slice);
694 }
695 }
696
697 // remove excess of slices (abouve m_count)
698 if (m_count != -1 && m_series->slices().size() > m_count) {
699 for (qsizetype i = m_series->slices().size() - 1; i >= m_count; i--) {
700 m_series->remove(slice: m_series->slices().at(i));
701 m_slices.removeAt(i);
702 }
703 }
704 }
705}
706
707void QPieModelMapperPrivate::removeData(qsizetype start, qsizetype end) {
708 if (m_model == 0 || m_series == 0)
709 return;
710
711 qsizetype removedCount = end - start + 1;
712 if (m_count != -1 && start >= m_first + m_count) {
713 return;
714 } else {
715 qsizetype toRemove = qMin(a: m_series->slices().size(),
716 b: removedCount); // first find how many items can actually be removed
717 qsizetype first = qMax(a: start,
718 b: m_first); // get the index of the first item that will be removed.
719 qsizetype last = qMin(a: first + toRemove - 1,
720 b: m_series->slices().size() + m_first
721 - 1); // get the index of the last item that will be removed.
722 for (qsizetype i = last; i >= first; i--) {
723 m_series->remove(slice: m_series->slices().at(i: i - m_first));
724 m_slices.removeAt(i: i - m_first);
725 }
726
727 if (m_count != -1) {
728 qsizetype itemsAvailable; // check how many are available to be added
729 if (m_orientation == Qt::Vertical)
730 itemsAvailable = m_model->rowCount() - m_first - m_series->slices().size();
731 else
732 itemsAvailable = m_model->columnCount() - m_first - m_series->slices().size();
733 qsizetype toBeAdded = qMin(a: itemsAvailable,
734 b: m_count
735 - m_series->slices().size()); // add not more items than there
736 // is space left to be filled.
737 qsizetype currentSize = m_series->slices().size();
738 if (toBeAdded > 0) {
739 for (qsizetype i = m_series->slices().size(); i < currentSize + toBeAdded; i++) {
740 QModelIndex valueIndex = valueModelIndex(sliceIndex: i - m_first);
741 QModelIndex labelIndex = labelModelIndex(sliceIndex: i - m_first);
742 if (valueIndex.isValid() && labelIndex.isValid()) {
743 QPieSlice *slice = new QPieSlice;
744 slice->setValue(m_model->data(index: valueIndex, role: Qt::DisplayRole).toDouble());
745 slice->setLabel(m_model->data(index: labelIndex, role: Qt::DisplayRole).toString());
746 m_series->insert(index: i, slice);
747 m_slices.insert(i, t: slice);
748 }
749 }
750 }
751 }
752 }
753}
754
755void QPieModelMapperPrivate::initializePieFromModel() {
756 if (m_model == nullptr || m_series == nullptr)
757 return;
758
759 blockSeriesSignals();
760 // clear current content
761 m_series->clear();
762 m_slices.clear();
763
764 // create the initial slices set
765 int slicePos = 0;
766 QModelIndex valueIndex = valueModelIndex(sliceIndex: slicePos);
767 QModelIndex labelIndex = labelModelIndex(sliceIndex: slicePos);
768 Q_Q(QPieModelMapper);
769 while (valueIndex.isValid() && labelIndex.isValid()) {
770 QPieSlice *slice = new QPieSlice;
771 slice->setLabel(m_model->data(index: labelIndex, role: Qt::DisplayRole).toString());
772 slice->setValue(m_model->data(index: valueIndex, role: Qt::DisplayRole).toDouble());
773 QObject::connect(sender: slice, signal: &QPieSlice::labelChanged, context: q, slot: &QPieModelMapper::onSliceLabelChanged);
774 QObject::connect(sender: slice, signal: &QPieSlice::valueChanged, context: q, slot: &QPieModelMapper::onSliceValueChanged);
775 m_series->append(slice);
776 m_slices.append(t: slice);
777 slicePos++;
778 valueIndex = valueModelIndex(sliceIndex: slicePos);
779 labelIndex = labelModelIndex(sliceIndex: slicePos);
780 }
781 blockSeriesSignals(block: false);
782}
783
784QT_END_NAMESPACE
785

Provided by KDAB

Privacy Policy
Start learning QML with our Intro Training
Find out more

source code of qtgraphs/src/graphs2d/piechart/qpiemodelmapper.cpp