summaryrefslogtreecommitdiffstats
path: root/src/charts/candlestickchart/candlestickchartitem.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'src/charts/candlestickchart/candlestickchartitem.cpp')
-rw-r--r--src/charts/candlestickchart/candlestickchartitem.cpp347
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