Revision control

++ // Copyright (C) 2017 The Qt Company Ltd.
++ // SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only
++
++ #include "qscatterdataproxy_p.h"
++ #include "qscatter3dseries_p.h"
++ #include "qabstract3daxis_p.h"
++
++ QT_BEGIN_NAMESPACE
++
++ /*!
++ * \class QScatterDataProxy
++ * \inmodule QtDataVisualization
++ * \brief The QScatterDataProxy class is the data proxy for 3D scatter graphs.
++ * \since QtDataVisualization 1.0
++ *
++ * A scatter data proxy handles adding, inserting, changing, and removing data
++ * items.
++ *
++ * QScatterDataProxy takes ownership of all
++ * QtDataVisualization::QScatterDataArray and QScatterDataItem objects passed to
++ * it.
++ *
++ * \sa {Qt Data Visualization Data Handling}
++ */
++
++ /*!
++ * \typedef QScatterDataArray
++ * \relates QScatterDataProxy
++ *
++ * A list of \l {QScatterDataItem} objects.
++ */
++
++ /*!
++ * \qmltype ScatterDataProxy
++ * \inqmlmodule QtDataVisualization
++ * \since QtDataVisualization 1.0
++ * \ingroup datavisualization_qml
++ * \nativetype QScatterDataProxy
++ * \inherits AbstractDataProxy
++ * \brief The data proxy for 3D scatter graphs.
++ *
++ * This type handles adding, inserting, changing, and removing data items.
++ *
++ * This type is uncreatable, but contains properties that are exposed via subtypes.
++ *
++ * \sa ItemModelScatterDataProxy, {Qt Data Visualization Data Handling}
++ */
++
++ /*!
++ * \qmlproperty int ScatterDataProxy::itemCount
++ * The number of items in the array.
++ */
++
++ /*!
++ * \qmlproperty Scatter3DSeries ScatterDataProxy::series
++ *
++ * The series this proxy is attached to.
++ */
++
++ /*!
++ * Constructs QScatterDataProxy with the given \a parent.
++ */
++ QScatterDataProxy::QScatterDataProxy(QObject *parent) :
++ QAbstractDataProxy(new QScatterDataProxyPrivate(this), parent)
++ {
++ }
++
++ /*!
++ * \internal
++ */
++ QScatterDataProxy::QScatterDataProxy(QScatterDataProxyPrivate *d, QObject *parent) :
++ QAbstractDataProxy(d, parent)
++ {
++ }
++
++ /*!
++ * Deletes the scatter data proxy.
++ */
++ QScatterDataProxy::~QScatterDataProxy()
++ {
++ }
++
++ /*!
++ * \property QScatterDataProxy::series
++ *
++ * \brief The series this proxy is attached to.
++ */
++ QScatter3DSeries *QScatterDataProxy::series() const
++ {
++ return static_cast<QScatter3DSeries *>(d_ptr->series());
++ }
++
++ /*!
++ * Takes ownership of the array \a newArray. Clears the existing array if the
++ * new array differs from it. If the arrays are the same, this function
++ * just triggers the arrayReset() signal.
++ *
++ * Passing a null array deletes the old array and creates a new empty array.
++ */
++ void QScatterDataProxy::resetArray(QScatterDataArray *newArray)
++ {
++ if (dptr()->m_dataArray != newArray)
++ dptr()->resetArray(newArray);
++
++ emit arrayReset();
++ emit itemCountChanged(itemCount());
++ }
++
++ /*!
++ * Replaces the item at the position \a index with the item \a item.
++ */
++ void QScatterDataProxy::setItem(int index, const QScatterDataItem &item)
++ {
++ dptr()->setItem(index, item);
++ emit itemsChanged(index, 1);
++ }
++
++ /*!
++ * Replaces the items starting from the position \a index with the items
++ * specified by \a items.
++ */
++ void QScatterDataProxy::setItems(int index, const QScatterDataArray &items)
++ {
++ dptr()->setItems(index, items);
++ emit itemsChanged(index, items.size());
++ }
++
++ /*!
++ * Adds the item \a item to the end of the array.
++ *
++ * Returns the index of the added item.
++ */
++ int QScatterDataProxy::addItem(const QScatterDataItem &item)
++ {
++ int addIndex = dptr()->addItem(item);
++ emit itemsAdded(addIndex, 1);
++ emit itemCountChanged(itemCount());
++ return addIndex;
++ }
++
++ /*!
++ * Adds the items specified by \a items to the end of the array.
++ *
++ * Returns the index of the first added item.
++ */
++ int QScatterDataProxy::addItems(const QScatterDataArray &items)
++ {
++ int addIndex = dptr()->addItems(items);
++ emit itemsAdded(addIndex, items.size());
++ emit itemCountChanged(itemCount());
++ return addIndex;
++ }
++
++ /*!
++ * Inserts the item \a item to the position \a index. If the index is equal to
++ * the data array size, the item is added to the array.
++ */
++ void QScatterDataProxy::insertItem(int index, const QScatterDataItem &item)
++ {
++ dptr()->insertItem(index, item);
++ emit itemsInserted(index, 1);
++ emit itemCountChanged(itemCount());
++ }
++
++ /*!
++ * Inserts the items specified by \a items to the position \a index. If the
++ * index is equal to data array size, the items are added to the array.
++ */
++ void QScatterDataProxy::insertItems(int index, const QScatterDataArray &items)
++ {
++ dptr()->insertItems(index, items);
++ emit itemsInserted(index, items.size());
++ emit itemCountChanged(itemCount());
++ }
++
++ /*!
++ * Removes the number of items specified by \a removeCount starting at the
++ * position \a index. Attempting to remove items past the end of
++ * the array does nothing.
++ */
++ void QScatterDataProxy::removeItems(int index, int removeCount)
++ {
++ if (index >= dptr()->m_dataArray->size())
++ return;
++
++ dptr()->removeItems(index, removeCount);
++ emit itemsRemoved(index, removeCount);
++ emit itemCountChanged(itemCount());
++ }
++
++ /*!
++ * \property QScatterDataProxy::itemCount
++ *
++ * \brief The number of items in the array.
++ */
++ int QScatterDataProxy::itemCount() const
++ {
++ return dptrc()->m_dataArray->size();
++ }
++
++ /*!
++ * Returns the pointer to the data array.
++ */
++ const QScatterDataArray *QScatterDataProxy::array() const
++ {
++ return dptrc()->m_dataArray;
++ }
++
++ /*!
++ * Returns the pointer to the item at the index \a index. It is guaranteed to be
++ * valid only until the next call that modifies data.
++ */
++ const QScatterDataItem *QScatterDataProxy::itemAt(int index) const
++ {
++ return &dptrc()->m_dataArray->at(index);
++ }
++
++ /*!
++ * \internal
++ */
++ QScatterDataProxyPrivate *QScatterDataProxy::dptr()
++ {
++ return static_cast<QScatterDataProxyPrivate *>(d_ptr.data());
++ }
++
++ /*!
++ * \internal
++ */
++ const QScatterDataProxyPrivate *QScatterDataProxy::dptrc() const
++ {
++ return static_cast<const QScatterDataProxyPrivate *>(d_ptr.data());
++ }
++
++ /*!
++ * \fn void QScatterDataProxy::arrayReset()
++ *
++ * This signal is emitted when the data array is reset.
++ * If the contents of the whole array are changed without calling resetArray(),
++ * this signal needs to be emitted to update the graph.
++ */
++
++ /*!
++ * \fn void QScatterDataProxy::itemsAdded(int startIndex, int count)
++ *
++ * This signal is emitted when the number of items specified by \a count is
++ * added starting at the position \a startIndex.
++ * If items are added to the array without calling addItem() or addItems(),
++ * this signal needs to be emitted to update the graph.
++ */
++
++ /*!
++ * \fn void QScatterDataProxy::itemsChanged(int startIndex, int count)
++ *
++ * This signal is emitted when the number of items specified by \a count is
++ * changed starting at the position \a startIndex.
++ * If items are changed in the array without calling setItem() or setItems(),
++ * this signal needs to be emitted to update the graph.
++ */
++
++ /*!
++ * \fn void QScatterDataProxy::itemsRemoved(int startIndex, int count)
++ *
++ * This signal is emitted when the number of rows specified by \a count is
++ * removed starting at the position \a startIndex.
++ * The index may be larger than the current array size if items are removed from
++ * the end. If items are removed from the array without calling removeItems(),
++ * this signal needs to be emitted to update the graph.
++ */
++
++ /*!
++ * \fn void QScatterDataProxy::itemsInserted(int startIndex, int count)
++ *
++ * This signal is emitted when the number of items specified by \a count is
++ * inserted starting at the position \a startIndex.
++ * If items are inserted into the array without calling insertItem() or
++ * insertItems(), this signal needs to be emitted to update the graph.
++ */
++
++ // QScatterDataProxyPrivate
++
++ QScatterDataProxyPrivate::QScatterDataProxyPrivate(QScatterDataProxy *q)
++ : QAbstractDataProxyPrivate(q, QAbstractDataProxy::DataTypeScatter),
++ m_dataArray(new QScatterDataArray)
++ {
++ }
++
++ QScatterDataProxyPrivate::~QScatterDataProxyPrivate()
++ {
++ m_dataArray->clear();
++ delete m_dataArray;
++ }
++
++ void QScatterDataProxyPrivate::resetArray(QScatterDataArray *newArray)
++ {
++ if (!newArray)
++ newArray = new QScatterDataArray;
++
++ if (newArray != m_dataArray) {
++ m_dataArray->clear();
++ delete m_dataArray;
++ m_dataArray = newArray;
++ }
++ }
++
++ void QScatterDataProxyPrivate::setItem(int index, const QScatterDataItem &item)
++ {
++ Q_ASSERT(index >= 0 && index < m_dataArray->size());
++ (*m_dataArray)[index] = item;
++ }
++
++ void QScatterDataProxyPrivate::setItems(int index, const QScatterDataArray &items)
++ {
++ Q_ASSERT(index >= 0 && (index + items.size()) <= m_dataArray->size());
++ for (int i = 0; i < items.size(); i++)
++ (*m_dataArray)[index++] = items[i];
++ }
++
++ int QScatterDataProxyPrivate::addItem(const QScatterDataItem &item)
++ {
++ int currentSize = m_dataArray->size();
++ m_dataArray->append(item);
++ return currentSize;
++ }
++
++ int QScatterDataProxyPrivate::addItems(const QScatterDataArray &items)
++ {
++ int currentSize = m_dataArray->size();
++ (*m_dataArray) += items;
++ return currentSize;
++ }
++
++ void QScatterDataProxyPrivate::insertItem(int index, const QScatterDataItem &item)
++ {
++ Q_ASSERT(index >= 0 && index <= m_dataArray->size());
++ m_dataArray->insert(index, item);
++ }
++
++ void QScatterDataProxyPrivate::insertItems(int index, const QScatterDataArray &items)
++ {
++ Q_ASSERT(index >= 0 && index <= m_dataArray->size());
++ for (int i = 0; i < items.size(); i++)
++ m_dataArray->insert(index++, items.at(i));
++ }
++
++ void QScatterDataProxyPrivate::removeItems(int index, int removeCount)
++ {
++ Q_ASSERT(index >= 0);
++ int maxRemoveCount = m_dataArray->size() - index;
++ removeCount = qMin(removeCount, maxRemoveCount);
++ m_dataArray->remove(index, removeCount);
++ }
++
++ void QScatterDataProxyPrivate::limitValues(QVector3D &minValues, QVector3D &maxValues,
++ QAbstract3DAxis *axisX, QAbstract3DAxis *axisY,
++ QAbstract3DAxis *axisZ) const
++ {
++ if (m_dataArray->isEmpty())
++ return;
++
++ const QVector3D &firstPos = m_dataArray->at(0).position();
++
++ float minX = firstPos.x();
++ float maxX = minX;
++ float minY = firstPos.y();
++ float maxY = minY;
++ float minZ = firstPos.z();
++ float maxZ = minZ;
++
++ if (m_dataArray->size() > 1) {
++ for (int i = 1; i < m_dataArray->size(); i++) {
++ const QVector3D &pos = m_dataArray->at(i).position();
++
++ float value = pos.x();
++ if (qIsNaN(value) || qIsInf(value))
++ continue;
++ if (isValidValue(minX, value, axisX))
++ minX = value;
++ if (maxX < value)
++ maxX = value;
++
++ value = pos.y();
++ if (qIsNaN(value) || qIsInf(value))
++ continue;
++ if (isValidValue(minY, value, axisY))
++ minY = value;
++ if (maxY < value)
++ maxY = value;
++
++ value = pos.z();
++ if (qIsNaN(value) || qIsInf(value))
++ continue;
++ if (isValidValue(minZ, value, axisZ))
++ minZ = value;
++ if (maxZ < value)
++ maxZ = value;
++ }
++ }
++
++ minValues.setX(minX);
++ minValues.setY(minY);
++ minValues.setZ(minZ);
++
++ maxValues.setX(maxX);
++ maxValues.setY(maxY);
++ maxValues.setZ(maxZ);
++ }
++
++ bool QScatterDataProxyPrivate::isValidValue(float axisValue, float value,
++ QAbstract3DAxis *axis) const
++ {
++ return (axisValue > value && (value > 0.0f
++ || (value == 0.0f && axis->d_ptr->allowZero())
++ || (value < 0.0f && axis->d_ptr->allowNegatives())));
++ }
++
++ void QScatterDataProxyPrivate::setSeries(QAbstract3DSeries *series)
++ {
++ QAbstractDataProxyPrivate::setSeries(series);
++ QScatter3DSeries *scatterSeries = static_cast<QScatter3DSeries *>(series);
++ emit qptr()->seriesChanged(scatterSeries);
++ }
++
++ QScatterDataProxy *QScatterDataProxyPrivate::qptr()
++ {
++ return static_cast<QScatterDataProxy *>(q_ptr);
++ }
++
++ QT_END_NAMESPACE