diff options
Diffstat (limited to 'src/charts/candlestickchart/candlestickchartitem.cpp')
-rw-r--r-- | src/charts/candlestickchart/candlestickchartitem.cpp | 347 |
1 files changed, 347 insertions, 0 deletions
diff --git a/src/charts/candlestickchart/candlestickchartitem.cpp b/src/charts/candlestickchart/candlestickchartitem.cpp new file mode 100644 index 00000000..ad64dd13 --- /dev/null +++ b/src/charts/candlestickchart/candlestickchartitem.cpp @@ -0,0 +1,347 @@ +/**************************************************************************** +** +** Copyright (C) 2016 The Qt Company Ltd. +** Contact: https://www.qt.io/licensing/ +** +** This file is part of the Qt Charts module of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:GPL$ +** Commercial License Usage +** Licensees holding valid commercial Qt licenses may use this file in +** accordance with the commercial license agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and The Qt Company. For licensing terms +** and conditions see https://www.qt.io/terms-conditions. For further +** information use the contact form at https://www.qt.io/contact-us. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3 or (at your option) any later version +** approved by the KDE Free Qt Foundation. The licenses are as published by +** the Free Software Foundation and appearing in the file LICENSE.GPL3 +** included in the packaging of this file. Please review the following +** information to ensure the GNU General Public License requirements will +** be met: https://www.gnu.org/licenses/gpl-3.0.html. +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include <QtCharts/QCandlestickSeries> +#include <QtCharts/QCandlestickSet> +#include <private/candlestickchartitem_p.h> +#include <private/candlestick_p.h> +#include <private/candlestickdata_p.h> +#include <private/qcandlestickseries_p.h> +#include <private/candlestickanimation_p.h> + +QT_CHARTS_BEGIN_NAMESPACE + +CandlestickChartItem::CandlestickChartItem(QCandlestickSeries *series, QGraphicsItem *item) + : ChartItem(series->d_func(), item), + m_series(series), + m_seriesIndex(0), + m_seriesCount(0), + m_timePeriod(0.0), + m_animation(nullptr) +{ + connect(series, SIGNAL(candlestickSetsAdded(QList<QCandlestickSet *>)), + this, SLOT(handleCandlestickSetsAdd(QList<QCandlestickSet *>))); + connect(series, SIGNAL(candlestickSetsRemoved(QList<QCandlestickSet *>)), + this, SLOT(handleCandlestickSetsRemove(QList<QCandlestickSet *>))); + + connect(series->d_func(), SIGNAL(updated()), this, SLOT(handleCandlesticksUpdated())); + connect(series->d_func(), SIGNAL(updatedLayout()), this, SLOT(handleLayoutUpdated())); + connect(series->d_func(), SIGNAL(updatedCandlesticks()), + this, SLOT(handleCandlesticksUpdated())); + + setZValue(ChartPresenter::CandlestickSeriesZValue); + + handleCandlestickSetsAdd(m_series->candlestickSets()); +} + +CandlestickChartItem::~CandlestickChartItem() +{ +} + +void CandlestickChartItem::setAnimation(CandlestickAnimation *animation) +{ + m_animation = animation; + + if (m_animation) { + foreach (Candlestick *item, m_candlesticks.values()) + m_animation->addCandlestick(item); + + handleDomainUpdated(); + } +} + +QRectF CandlestickChartItem::boundingRect() const +{ + return m_boundingRect; +} + +void CandlestickChartItem::paint(QPainter *painter, const QStyleOptionGraphicsItem *option, + QWidget *widget) +{ + Q_UNUSED(painter); + Q_UNUSED(option); + Q_UNUSED(widget); +} + +void CandlestickChartItem::handleDomainUpdated() +{ + if ((domain()->size().width() <= 0) || (domain()->size().height() <= 0)) + return; + + // Set bounding rectangle to same as domain size. Add one pixel at the top (-1.0) and the bottom + // as 0.0 would snip a bit off from the wick at the grid line. + m_boundingRect.setRect(0.0, -1.0, domain()->size().width(), domain()->size().height() + 1.0); + + foreach (Candlestick *item, m_candlesticks.values()) { + item->updateGeometry(domain()); + + if (m_animation) + presenter()->startAnimation(m_animation->candlestickAnimation(item)); + } +} + +void CandlestickChartItem::handleLayoutUpdated() +{ + bool timestampChanged = false; + foreach (QCandlestickSet *set, m_candlesticks.keys()) { + qreal oldTimestamp = m_candlesticks.value(set)->m_data.m_timestamp; + qreal newTimestamp = set->timestamp(); + if (Q_UNLIKELY(oldTimestamp != newTimestamp)) { + removeTimestamp(oldTimestamp); + addTimestamp(newTimestamp); + timestampChanged = true; + } + } + if (timestampChanged) + updateTimePeriod(); + + foreach (Candlestick *item, m_candlesticks.values()) { + if (m_animation) + m_animation->setAnimationStart(item); + + item->setTimePeriod(m_timePeriod); + item->setMaximumColumnWidth(m_series->maximumColumnWidth()); + item->setMinimumColumnWidth(m_series->minimumColumnWidth()); + item->setBodyWidth(m_series->bodyWidth()); + item->setCapsWidth(m_series->capsWidth()); + + bool dirty = updateCandlestickGeometry(item, item->m_data.m_index); + if (dirty && m_animation) + presenter()->startAnimation(m_animation->candlestickChangeAnimation(item)); + else + item->updateGeometry(domain()); + } +} + +void CandlestickChartItem::handleCandlesticksUpdated() +{ + foreach (QCandlestickSet *set, m_candlesticks.keys()) + updateCandlestickAppearance(m_candlesticks.value(set), set); +} + +void CandlestickChartItem::handleCandlestickSeriesChange() +{ + int seriesIndex = 0; + int seriesCount = 0; + + int index = 0; + foreach (QAbstractSeries *series, m_series->chart()->series()) { + if (series->type() == QAbstractSeries::SeriesTypeCandlestick) { + if (m_series == static_cast<QCandlestickSeries *>(series)) + seriesIndex = index; + index++; + } + } + seriesCount = index; + + bool changed; + if ((m_seriesIndex != seriesIndex) || (m_seriesCount != seriesCount)) + changed = true; + else + changed = false; + + if (changed) { + m_seriesIndex = seriesIndex; + m_seriesCount = seriesCount; + handleDataStructureChanged(); + } +} + +void CandlestickChartItem::handleCandlestickSetsAdd(const QList<QCandlestickSet *> &sets) +{ + foreach (QCandlestickSet *set, sets) { + Candlestick *item = m_candlesticks.value(set, 0); + if (item) { + qWarning() << "There is already a candlestick for this set in the hash"; + continue; + } + + item = new Candlestick(set, domain(), this); + m_candlesticks.insert(set, item); + addTimestamp(set->timestamp()); + + connect(item, SIGNAL(clicked(QCandlestickSet *)), + m_series, SIGNAL(clicked(QCandlestickSet *))); + connect(item, SIGNAL(hovered(bool, QCandlestickSet *)), + m_series, SIGNAL(hovered(bool, QCandlestickSet *))); + connect(item, SIGNAL(pressed(QCandlestickSet *)), + m_series, SIGNAL(pressed(QCandlestickSet *))); + connect(item, SIGNAL(released(QCandlestickSet *)), + m_series, SIGNAL(released(QCandlestickSet *))); + connect(item, SIGNAL(doubleClicked(QCandlestickSet *)), + m_series, SIGNAL(doubleClicked(QCandlestickSet *))); + connect(item, SIGNAL(clicked(QCandlestickSet *)), set, SIGNAL(clicked())); + connect(item, SIGNAL(hovered(bool, QCandlestickSet *)), set, SIGNAL(hovered(bool))); + connect(item, SIGNAL(pressed(QCandlestickSet *)), set, SIGNAL(pressed())); + connect(item, SIGNAL(released(QCandlestickSet *)), set, SIGNAL(released())); + connect(item, SIGNAL(doubleClicked(QCandlestickSet *)), set, SIGNAL(doubleClicked())); + } + + handleDataStructureChanged(); +} + +void CandlestickChartItem::handleCandlestickSetsRemove(const QList<QCandlestickSet *> &sets) +{ + foreach (QCandlestickSet *set, sets) { + Candlestick *item = m_candlesticks.value(set); + + m_candlesticks.remove(set); + removeTimestamp(set->timestamp()); + + if (m_animation) { + ChartAnimation *animation = m_animation->candlestickAnimation(item); + if (animation) { + animation->stop(); + delete animation; + } + } + + delete item; + } + + handleDataStructureChanged(); +} + +void CandlestickChartItem::handleDataStructureChanged() +{ + updateTimePeriod(); + + for (int i = 0; i < m_series->count(); ++i) { + QCandlestickSet *set = m_series->candlestickSets().at(i); + Candlestick *item = m_candlesticks.value(set); + + updateCandlestickGeometry(item, i); + updateCandlestickAppearance(item, set); + + item->updateGeometry(domain()); + + if (m_animation) + m_animation->addCandlestick(item); + } + + handleDomainUpdated(); +} + +bool CandlestickChartItem::updateCandlestickGeometry(Candlestick *item, int index) +{ + bool changed = false; + + QCandlestickSet *set = m_series->candlestickSets().at(index); + CandlestickData &data = item->m_data; + + if ((data.m_open != set->open()) + || (data.m_high != set->high()) + || (data.m_low != set->low()) + || (data.m_close != set->close())) { + changed = true; + } + + data.m_timestamp = set->timestamp(); + data.m_open = set->open(); + data.m_high = set->high(); + data.m_low = set->low(); + data.m_close = set->close(); + data.m_index = index; + + data.m_maxX = domain()->maxX(); + data.m_minX = domain()->minX(); + data.m_maxY = domain()->maxY(); + data.m_minY = domain()->minY(); + + data.m_series = m_series; + data.m_seriesIndex = m_seriesIndex; + data.m_seriesCount = m_seriesCount; + + return changed; +} + +void CandlestickChartItem::updateCandlestickAppearance(Candlestick *item, QCandlestickSet *set) +{ + item->setTimePeriod(m_timePeriod); + item->setMaximumColumnWidth(m_series->maximumColumnWidth()); + item->setMinimumColumnWidth(m_series->minimumColumnWidth()); + item->setBodyWidth(m_series->bodyWidth()); + item->setBodyOutlineVisible(m_series->bodyOutlineVisible()); + item->setCapsWidth(m_series->capsWidth()); + item->setCapsVisible(m_series->capsVisible()); + item->setIncreasingColor(m_series->increasingColor()); + item->setDecreasingColor(m_series->decreasingColor()); + + // Set the decorative issues for the candlestick so that + // the brush and pen already defined for the set are kept. + if (set->brush() == Qt::NoBrush) + item->setBrush(m_series->brush()); + else + item->setBrush(set->brush()); + + if (set->pen() == Qt::NoPen) + item->setPen(m_series->pen()); + else + item->setPen(set->pen()); +} + +void CandlestickChartItem::addTimestamp(qreal timestamp) +{ + int index = 0; + for (int i = m_timestamps.count() - 1; i >= 0; --i) { + if (timestamp > m_timestamps.at(i)) { + index = i + 1; + break; + } + } + m_timestamps.insert(index, timestamp); +} + +void CandlestickChartItem::removeTimestamp(qreal timestamp) +{ + m_timestamps.removeOne(timestamp); +} + +void CandlestickChartItem::updateTimePeriod() +{ + if (m_timestamps.count() == 0) { + m_timePeriod = 0; + return; + } + + if (m_timestamps.count() == 1) { + m_timePeriod = qAbs(domain()->maxX() - domain()->minX()); + return; + } + + qreal timePeriod = qAbs(m_timestamps.at(1) - m_timestamps.at(0)); + for (int i = 1; i < m_timestamps.count(); ++i) { + timePeriod = qMin(timePeriod, qAbs(m_timestamps.at(i) - m_timestamps.at(i - 1))); + } + m_timePeriod = timePeriod; +} + +#include "moc_candlestickchartitem_p.cpp" + +QT_CHARTS_END_NAMESPACE |