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

Provided by KDAB

Privacy Policy
Learn to use CMake with our Intro Training
Find out more

source code of qtgraphs/src/graphs2d/xychart/qxymodelmapper.cpp