summaryrefslogtreecommitdiffstats
path: root/tests/manual
diff options
context:
space:
mode:
authorAlexander Mishin <apmishin@yandex.com>2016-02-09 21:49:53 +0300
committerMiikka Heikkinen <miikka.heikkinen@qt.io>2016-05-25 11:47:43 +0000
commitfacc2941efbfb8c9f40e363f0ea881653f6b4393 (patch)
treeae5ef712e4abbe47d60704fd0978f7533c7edbdd /tests/manual
parente9a2e2a5e9c023c872e39e39fb2a8b0a31820577 (diff)
Added candlestick chart type
- added QCandlestickSeries - added QCandlestickSet - added QCandlestickLegendMarker - added model mappers - added Candlestick, CandlestickChartItem, CandlestickData - added SeriesTypeCandlestick to SeriesType enum - added LegendMarkerTypeCandlestick to LegendMarkerType enum - added candlestick chart example - added QML candlestick chart example - added candlestick tester - added autotests - added documentation [ChangeLog][CandlestickChart] Added new chart type: Candlestick Chart. Task-number: QTBUG-50544 Change-Id: I17d18dfa23e0ea209bf51ab1e349585b9cb50a8f Reviewed-by: Miikka Heikkinen <miikka.heikkinen@qt.io>
Diffstat (limited to 'tests/manual')
-rw-r--r--tests/manual/candlesticktester/candlesticktester.pro13
-rw-r--r--tests/manual/candlesticktester/customtablemodel.cpp160
-rw-r--r--tests/manual/candlesticktester/customtablemodel.h73
-rw-r--r--tests/manual/candlesticktester/main.cpp43
-rw-r--r--tests/manual/candlesticktester/mainwidget.cpp691
-rw-r--r--tests/manual/candlesticktester/mainwidget.h108
-rw-r--r--tests/manual/manual.pro3
7 files changed, 1090 insertions, 1 deletions
diff --git a/tests/manual/candlesticktester/candlesticktester.pro b/tests/manual/candlesticktester/candlesticktester.pro
new file mode 100644
index 00000000..fd927b6e
--- /dev/null
+++ b/tests/manual/candlesticktester/candlesticktester.pro
@@ -0,0 +1,13 @@
+!include( ../../tests.pri ) {
+ error( "Couldn't find the test.pri file!" )
+}
+
+QT += widgets
+
+SOURCES += main.cpp \
+ mainwidget.cpp \
+ customtablemodel.cpp
+
+HEADERS += \
+ mainwidget.h \
+ customtablemodel.h
diff --git a/tests/manual/candlesticktester/customtablemodel.cpp b/tests/manual/candlesticktester/customtablemodel.cpp
new file mode 100644
index 00000000..e0122429
--- /dev/null
+++ b/tests/manual/candlesticktester/customtablemodel.cpp
@@ -0,0 +1,160 @@
+/****************************************************************************
+**
+** 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/QCandlestickSet>
+#include <QtCore/QRect>
+#include <QtCore/QVector>
+#include <QtGui/QColor>
+#include "customtablemodel.h"
+
+CustomTableModel::CustomTableModel(QObject *parent)
+ : QAbstractTableModel(parent)
+{
+ m_categories.append(QStringLiteral("Timestamp"));
+ m_categories.append(QStringLiteral("Open"));
+ m_categories.append(QStringLiteral("High"));
+ m_categories.append(QStringLiteral("Low"));
+ m_categories.append(QStringLiteral("Close"));
+}
+
+CustomTableModel::~CustomTableModel()
+{
+ qDeleteAll(m_data);
+}
+
+int CustomTableModel::rowCount(const QModelIndex &parent) const
+{
+ Q_UNUSED(parent)
+
+ return m_data.count();
+}
+
+int CustomTableModel::columnCount(const QModelIndex &parent) const
+{
+ Q_UNUSED(parent)
+
+ return m_categories.count();
+}
+
+QVariant CustomTableModel::headerData(int section, Qt::Orientation orientation, int role) const
+{
+ if (role != Qt::DisplayRole)
+ return QVariant();
+
+ if (orientation == Qt::Horizontal)
+ return m_categories[section];
+ else
+ return QStringLiteral("%1").arg(section);
+}
+
+bool CustomTableModel::setData(const QModelIndex &index, const QVariant &value, int role)
+{
+ if (index.isValid() && role == Qt::EditRole) {
+ m_data[index.row()]->replace(index.column(), value.toDouble());
+ emit dataChanged(index, index);
+
+ return true;
+ }
+
+ return false;
+}
+
+QVariant CustomTableModel::data(const QModelIndex &index, int role) const
+{
+ switch (role) {
+ case Qt::DisplayRole:
+ // fall through
+ case Qt::EditRole:
+ return m_data[index.row()]->at(index.column());
+ case Qt::BackgroundRole:
+ foreach (QRect rect, m_mapping) {
+ if (rect.contains(index.column(), index.row()))
+ return QColor(m_mapping.key(rect));
+ }
+ // cell is not mapped, return white color
+ return QColor(Qt::white);
+ default:
+ return QVariant();
+ }
+}
+
+Qt::ItemFlags CustomTableModel::flags(const QModelIndex &index) const
+{
+ return QAbstractItemModel::flags(index) | Qt::ItemIsEditable;
+}
+
+bool CustomTableModel::insertRows(int row, int count, const QModelIndex &parent)
+{
+ beginInsertRows(parent, row, row + count - 1);
+ m_data.append(new QVector<qreal>(columnCount()));
+ endInsertRows();
+
+ return true;
+}
+
+bool CustomTableModel::removeRows(int row, int count, const QModelIndex &parent)
+{
+ beginRemoveRows(parent, row, row + count - 1);
+ for (int i = row + count; i >= row; --i)
+ m_data.removeAt(i);
+ endRemoveRows();
+
+ return true;
+}
+
+void CustomTableModel::addRow(QCandlestickSet *set)
+{
+ bool changed = insertRows(m_data.count(), 1);
+
+ if (changed) {
+ QVector<qreal> *row = m_data.last();
+ row->insert(0, set->timestamp());
+ row->insert(1, set->open());
+ row->insert(2, set->high());
+ row->insert(3, set->low());
+ row->insert(4, set->close());
+ }
+}
+
+void CustomTableModel::clearRows()
+{
+ bool changed = removeRows(0, m_data.count());
+ if (changed)
+ m_data.clear();
+}
+
+void CustomTableModel::addMapping(QString color, QRect area)
+{
+ m_mapping.insertMulti(color, area);
+}
+
+void CustomTableModel::clearMapping()
+{
+ m_mapping.clear();
+}
diff --git a/tests/manual/candlesticktester/customtablemodel.h b/tests/manual/candlesticktester/customtablemodel.h
new file mode 100644
index 00000000..4a8965c3
--- /dev/null
+++ b/tests/manual/candlesticktester/customtablemodel.h
@@ -0,0 +1,73 @@
+/****************************************************************************
+**
+** 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$
+**
+****************************************************************************/
+
+#ifndef CUSTOMTABLEMODEL_H
+#define CUSTOMTABLEMODEL_H
+
+#include <QtCharts/QChartGlobal>
+#include <QtCore/QAbstractTableModel>
+#include <QtCore/QHash>
+#include <QtCore/QRect>
+
+QT_CHARTS_BEGIN_NAMESPACE
+class QCandlestickSet;
+QT_CHARTS_END_NAMESPACE
+
+QT_CHARTS_USE_NAMESPACE
+
+class CustomTableModel : public QAbstractTableModel
+{
+ Q_OBJECT
+
+public:
+ explicit CustomTableModel(QObject *parent = nullptr);
+ virtual ~CustomTableModel();
+
+ int rowCount(const QModelIndex &parent = QModelIndex()) const;
+ int columnCount(const QModelIndex &parent = QModelIndex()) const;
+ QVariant headerData(int section, Qt::Orientation orientation, int role = Qt::DisplayRole) const;
+ bool setData(const QModelIndex &index, const QVariant &value, int role = Qt::EditRole);
+ QVariant data(const QModelIndex &index, int role = Qt::DisplayRole) const;
+ Qt::ItemFlags flags(const QModelIndex &index) const;
+ bool insertRows(int row, int count, const QModelIndex &parent = QModelIndex());
+ bool removeRows(int row, int count, const QModelIndex &parent = QModelIndex());
+
+ void addRow(QCandlestickSet *set);
+ void clearRows();
+
+ void addMapping(QString color, QRect area);
+ void clearMapping();
+
+private:
+ QStringList m_categories;
+ QList<QVector<qreal> *> m_data;
+ QHash<QString, QRect> m_mapping;
+};
+
+#endif // CUSTOMTABLEMODEL_H
diff --git a/tests/manual/candlesticktester/main.cpp b/tests/manual/candlesticktester/main.cpp
new file mode 100644
index 00000000..3c893315
--- /dev/null
+++ b/tests/manual/candlesticktester/main.cpp
@@ -0,0 +1,43 @@
+/****************************************************************************
+**
+** 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 <QtWidgets/QApplication>
+#include "mainwidget.h"
+
+int main(int argc, char *argv[])
+{
+ QApplication a(argc, argv);
+
+ MainWidget w;
+ w.setWindowTitle(QStringLiteral("Candlestick Chart Tester"));
+ w.resize(1280, 720);
+ w.show();
+
+ return a.exec();
+}
diff --git a/tests/manual/candlesticktester/mainwidget.cpp b/tests/manual/candlesticktester/mainwidget.cpp
new file mode 100644
index 00000000..7364f023
--- /dev/null
+++ b/tests/manual/candlesticktester/mainwidget.cpp
@@ -0,0 +1,691 @@
+/****************************************************************************
+**
+** 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/QBarCategoryAxis>
+#include <QtCharts/QCandlestickSeries>
+#include <QtCharts/QCandlestickSet>
+#include <QtCharts/QDateTimeAxis>
+#include <QtCharts/QHCandlestickModelMapper>
+#include <QtCharts/QValueAxis>
+#include <QtCore/QDateTime>
+#include <QtCore/QDebug>
+#include <QtWidgets/QCheckBox>
+#include <QtWidgets/QComboBox>
+#include <QtWidgets/QDoubleSpinBox>
+#include <QtWidgets/QGridLayout>
+#include <QtWidgets/QHeaderView>
+#include <QtWidgets/QLabel>
+#include <QtWidgets/QPushButton>
+#include <QtWidgets/QTableView>
+#include "customtablemodel.h"
+#include "mainwidget.h"
+
+QT_CHARTS_USE_NAMESPACE
+
+MainWidget::MainWidget(QWidget *parent)
+ : QWidget(parent),
+ m_chart(new QChart()),
+ m_chartView(new QChartView(m_chart, this)),
+ m_axisX(nullptr),
+ m_axisY(nullptr),
+ m_maximumColumnWidth(-1.0),
+ m_minimumColumnWidth(5.0),
+ m_bodyOutlineVisible(true),
+ m_capsVisible(false),
+ m_bodyWidth(0.5),
+ m_capsWidth(0.5),
+ m_customIncreasingColor(false),
+ m_customDecreasingColor(false),
+ m_hModelMapper(new QHCandlestickModelMapper(this))
+{
+ qsrand(QDateTime::currentDateTime().toTime_t());
+
+ m_chartView->setRenderHint(QPainter::Antialiasing, false);
+
+ m_hModelMapper->setModel(new CustomTableModel(this));
+ m_hModelMapper->setTimestampColumn(0);
+ m_hModelMapper->setOpenColumn(1);
+ m_hModelMapper->setHighColumn(2);
+ m_hModelMapper->setLowColumn(3);
+ m_hModelMapper->setCloseColumn(4);
+
+ QGridLayout *mainLayout = new QGridLayout();
+ mainLayout->addLayout(createSeriesControlsLayout(), 0, 0);
+ mainLayout->addLayout(createSetsControlsLayout(), 1, 0);
+ mainLayout->addLayout(createCandlestickControlsLayout(), 2, 0);
+ mainLayout->addLayout(createMiscellaneousControlsLayout(), 3, 0);
+ mainLayout->addWidget(m_chartView, 0, 1, mainLayout->rowCount() + 1, 1);
+ mainLayout->addLayout(createModelMapperControlsLayout(), 0, 2, mainLayout->rowCount(), 1);
+ setLayout(mainLayout);
+
+ addSeries();
+}
+
+MainWidget::~MainWidget()
+{
+}
+
+QGridLayout *MainWidget::createSeriesControlsLayout()
+{
+ QGridLayout *layout = new QGridLayout();
+ int row = 0;
+
+ layout->addWidget(new QLabel(QStringLiteral("Series controls:")), row, 0, Qt::AlignLeft);
+
+ QPushButton *addSeriesButton = new QPushButton(QStringLiteral("Add a series"));
+ connect(addSeriesButton, SIGNAL(clicked(bool)), this, SLOT(addSeries()));
+ layout->addWidget(addSeriesButton, row++, 1, Qt::AlignLeft);
+
+ QPushButton *removeSeriesButton = new QPushButton(QStringLiteral("Remove a series"));
+ connect(removeSeriesButton, SIGNAL(clicked(bool)), this, SLOT(removeSeries()));
+ layout->addWidget(removeSeriesButton, row++, 1, Qt::AlignLeft);
+
+ QPushButton *removeAllSeriesButton = new QPushButton(QStringLiteral("Remove all series"));
+ connect(removeAllSeriesButton, SIGNAL(clicked(bool)), this, SLOT(removeAllSeries()));
+ layout->addWidget(removeAllSeriesButton, row++, 1, Qt::AlignLeft);
+
+ return layout;
+}
+
+QGridLayout *MainWidget::createSetsControlsLayout()
+{
+ QGridLayout *layout = new QGridLayout();
+ int row = 0;
+
+ layout->addWidget(new QLabel(QStringLiteral("Sets controls:")), row, 0, Qt::AlignLeft);
+
+ QPushButton *addSetButton = new QPushButton(QStringLiteral("Add a set"));
+ connect(addSetButton, SIGNAL(clicked(bool)), this, SLOT(addSet()));
+ layout->addWidget(addSetButton, row++, 1, Qt::AlignLeft);
+
+ QPushButton *insertSetButton = new QPushButton(QStringLiteral("Insert a set"));
+ connect(insertSetButton, SIGNAL(clicked(bool)), this, SLOT(insertSet()));
+ layout->addWidget(insertSetButton, row++, 1, Qt::AlignLeft);
+
+ QPushButton *removeSetButton = new QPushButton(QStringLiteral("Remove a set"));
+ connect(removeSetButton, SIGNAL(clicked(bool)), this, SLOT(removeSet()));
+ layout->addWidget(removeSetButton, row++, 1, Qt::AlignLeft);
+
+ QPushButton *removeAllSetsButton = new QPushButton(QStringLiteral("Remove all sets"));
+ connect(removeAllSetsButton, SIGNAL(clicked(bool)), this, SLOT(removeAllSets()));
+ layout->addWidget(removeAllSetsButton, row++, 1, Qt::AlignLeft);
+
+ return layout;
+}
+
+QGridLayout *MainWidget::createCandlestickControlsLayout()
+{
+ QGridLayout *layout = new QGridLayout();
+ int row = 0;
+
+ layout->addWidget(new QLabel(QStringLiteral("Maximum column width:")), row, 0, Qt::AlignLeft);
+ QDoubleSpinBox *maximumColumnWidthSpinBox = new QDoubleSpinBox();
+ maximumColumnWidthSpinBox->setRange(-1.0, 1024.0);
+ maximumColumnWidthSpinBox->setDecimals(0);
+ maximumColumnWidthSpinBox->setValue(m_maximumColumnWidth);
+ maximumColumnWidthSpinBox->setSingleStep(1.0);
+ connect(maximumColumnWidthSpinBox, SIGNAL(valueChanged(double)),
+ this, SLOT(changeMaximumColumnWidth(double)));
+ layout->addWidget(maximumColumnWidthSpinBox, row++, 1, Qt::AlignLeft);
+
+ layout->addWidget(new QLabel(QStringLiteral("Minimum column width:")), row, 0, Qt::AlignLeft);
+ QDoubleSpinBox *minimumColumnWidthSpinBox = new QDoubleSpinBox();
+ minimumColumnWidthSpinBox->setRange(-1.0, 1024.0);
+ minimumColumnWidthSpinBox->setDecimals(0);
+ minimumColumnWidthSpinBox->setValue(m_minimumColumnWidth);
+ minimumColumnWidthSpinBox->setSingleStep(1.0);
+ connect(minimumColumnWidthSpinBox, SIGNAL(valueChanged(double)),
+ this, SLOT(changeMinimumColumnWidth(double)));
+ layout->addWidget(minimumColumnWidthSpinBox, row++, 1, Qt::AlignLeft);
+
+ QCheckBox *bodyOutlineVisible = new QCheckBox(QStringLiteral("Body outline visible"));
+ connect(bodyOutlineVisible, SIGNAL(toggled(bool)), this, SLOT(bodyOutlineVisibleToggled(bool)));
+ bodyOutlineVisible->setChecked(m_bodyOutlineVisible);
+ layout->addWidget(bodyOutlineVisible, row++, 0, Qt::AlignLeft);
+
+ QCheckBox *capsVisible = new QCheckBox(QStringLiteral("Caps visible"));
+ connect(capsVisible, SIGNAL(toggled(bool)), this, SLOT(capsVisibleToggled(bool)));
+ capsVisible->setChecked(m_capsVisible);
+ layout->addWidget(capsVisible, row++, 0, Qt::AlignLeft);
+
+ layout->addWidget(new QLabel(QStringLiteral("Candlestick body width:")), row, 0, Qt::AlignLeft);
+ QDoubleSpinBox *bodyWidthSpinBox = new QDoubleSpinBox();
+ bodyWidthSpinBox->setRange(-1.0, 2.0);
+ bodyWidthSpinBox->setValue(m_bodyWidth);
+ bodyWidthSpinBox->setSingleStep(0.1);
+ connect(bodyWidthSpinBox, SIGNAL(valueChanged(double)), this, SLOT(changeBodyWidth(double)));
+ layout->addWidget(bodyWidthSpinBox, row++, 1, Qt::AlignLeft);
+
+ layout->addWidget(new QLabel(QStringLiteral("Candlestick caps width:")), row, 0, Qt::AlignLeft);
+ QDoubleSpinBox *capsWidthSpinBox = new QDoubleSpinBox();
+ capsWidthSpinBox->setRange(-1.0, 2.0);
+ capsWidthSpinBox->setValue(m_capsWidth);
+ capsWidthSpinBox->setSingleStep(0.1);
+ connect(capsWidthSpinBox, SIGNAL(valueChanged(double)), this, SLOT(changeCapsWidth(double)));
+ layout->addWidget(capsWidthSpinBox, row++, 1, Qt::AlignLeft);
+
+ QCheckBox *increasingColor = new QCheckBox(QStringLiteral("Custom increasing color (only S1)"));
+ connect(increasingColor, SIGNAL(toggled(bool)), this, SLOT(customIncreasingColorToggled(bool)));
+ increasingColor->setChecked(m_customIncreasingColor);
+ layout->addWidget(increasingColor, row++, 0, 1, 2, Qt::AlignLeft);
+
+ QCheckBox *decreasingColor = new QCheckBox(QStringLiteral("Custom decreasing color (only S1)"));
+ connect(decreasingColor, SIGNAL(toggled(bool)), this, SLOT(customDecreasingColorToggled(bool)));
+ decreasingColor->setChecked(m_customDecreasingColor);
+ layout->addWidget(decreasingColor, row++, 0, 1, 2, Qt::AlignLeft);
+
+ return layout;
+}
+
+QGridLayout *MainWidget::createMiscellaneousControlsLayout()
+{
+ QGridLayout *layout = new QGridLayout();
+ int row = 0;
+
+ layout->addWidget(new QLabel(QStringLiteral("Miscellaneous:")), row, 0, Qt::AlignLeft);
+
+ QCheckBox *antialiasingCheckBox = new QCheckBox(QStringLiteral("Antialiasing"));
+ connect(antialiasingCheckBox, SIGNAL(toggled(bool)), this, SLOT(antialiasingToggled(bool)));
+ antialiasingCheckBox->setChecked(false);
+ layout->addWidget(antialiasingCheckBox, row++, 1, Qt::AlignLeft);
+
+ QCheckBox *animationCheckBox = new QCheckBox(QStringLiteral("Animation"));
+ connect(animationCheckBox, SIGNAL(toggled(bool)), this, SLOT(animationToggled(bool)));
+ animationCheckBox->setChecked(false);
+ layout->addWidget(animationCheckBox, row++, 1, Qt::AlignLeft);
+
+ QCheckBox *legendCheckBox = new QCheckBox(QStringLiteral("Legend"));
+ connect(legendCheckBox, SIGNAL(toggled(bool)), this, SLOT(legendToggled(bool)));
+ legendCheckBox->setChecked(true);
+ layout->addWidget(legendCheckBox, row++, 1, Qt::AlignLeft);
+
+ QCheckBox *titleCheckBox = new QCheckBox(QStringLiteral("Title"));
+ connect(titleCheckBox, SIGNAL(toggled(bool)), this, SLOT(titleToggled(bool)));
+ titleCheckBox->setChecked(true);
+ layout->addWidget(titleCheckBox, row++, 1, Qt::AlignLeft);
+
+ layout->addWidget(new QLabel(QStringLiteral("Chart theme:")), row, 0, Qt::AlignLeft);
+ QComboBox *chartThemeComboBox = new QComboBox();
+ chartThemeComboBox->addItem(QStringLiteral("Light"));
+ chartThemeComboBox->addItem(QStringLiteral("Blue Cerulean"));
+ chartThemeComboBox->addItem(QStringLiteral("Dark"));
+ chartThemeComboBox->addItem(QStringLiteral("Brown Sand"));
+ chartThemeComboBox->addItem(QStringLiteral("Blue Ncs"));
+ chartThemeComboBox->addItem(QStringLiteral("High Contrast"));
+ chartThemeComboBox->addItem(QStringLiteral("Blue Icy"));
+ chartThemeComboBox->addItem(QStringLiteral("Qt"));
+ connect(chartThemeComboBox,SIGNAL(currentIndexChanged(int)),this,SLOT(changeChartTheme(int)));
+ layout->addWidget(chartThemeComboBox, row++, 1, Qt::AlignLeft);
+
+ layout->addWidget(new QLabel(QStringLiteral("Axis X:")), row, 0, Qt::AlignLeft);
+ QComboBox *axisXComboBox = new QComboBox();
+ axisXComboBox->addItem(QStringLiteral("BarCategory"));
+ axisXComboBox->addItem(QStringLiteral("DateTime"));
+ axisXComboBox->addItem(QStringLiteral("Value"));
+ connect(axisXComboBox, SIGNAL(currentIndexChanged(int)), this, SLOT(changeAxisX(int)));
+ layout->addWidget(axisXComboBox, row++, 1, Qt::AlignLeft);
+
+ return layout;
+}
+
+QGridLayout *MainWidget::createModelMapperControlsLayout()
+{
+ QGridLayout *layout = new QGridLayout();
+ int row = 0;
+
+ layout->addWidget(new QLabel(QStringLiteral("First series:")), row, 0, Qt::AlignLeft);
+
+ QPushButton *attachModelMapperButton = new QPushButton(QStringLiteral("Attach model mapper"));
+ connect(attachModelMapperButton, SIGNAL(clicked(bool)), this, SLOT(attachModelMapper()));
+ layout->addWidget(attachModelMapperButton, row++, 1, Qt::AlignLeft);
+
+ QPushButton *detachModelMappeButton = new QPushButton(QStringLiteral("Detach model mapper"));
+ connect(detachModelMappeButton, SIGNAL(clicked(bool)), this, SLOT(detachModelMapper()));
+ layout->addWidget(detachModelMappeButton, row++, 1, Qt::AlignLeft);
+
+ QTableView *tableView = new QTableView();
+ tableView->setMinimumSize(320, 480);
+ tableView->setMaximumSize(320, 480);
+ tableView->horizontalHeader()->setSectionResizeMode(QHeaderView::Stretch);
+ tableView->verticalHeader()->setSectionResizeMode(QHeaderView::Stretch);
+ Q_ASSERT_X(m_hModelMapper->model(), Q_FUNC_INFO, "Model is not initialized");
+ tableView->setModel(m_hModelMapper->model());
+ layout->addWidget(tableView, row++, 0, 1, 2, Qt::AlignLeft);
+
+ layout->addItem(new QSpacerItem(1, 1, QSizePolicy::Fixed, QSizePolicy::Expanding), row++, 0);
+
+ return layout;
+}
+
+qreal MainWidget::randomValue(int min, int max) const
+{
+ return (qrand() / (qreal(RAND_MAX) + 1)) * ((qMax(min, max) - qMin(min, max)) + qMin(min, max));
+}
+
+QCandlestickSet *MainWidget::randomSet(qreal timestamp)
+{
+ QCandlestickSet *set = new QCandlestickSet(timestamp);
+ set->setOpen(randomValue(4, 11));
+ set->setHigh(randomValue(12, 15));
+ set->setLow(randomValue(0, 3));
+ set->setClose(randomValue(4, 11));
+
+ return set;
+}
+
+void MainWidget::updateAxes()
+{
+ if (m_chart->axes().isEmpty())
+ m_chart->createDefaultAxes();
+
+ QCandlestickSeries *series;
+ if (!m_chart->series().isEmpty())
+ series = qobject_cast<QCandlestickSeries *>(m_chart->series().at(0));
+ else
+ series = nullptr;
+
+ m_axisX = m_chart->axes(Qt::Horizontal).first();
+ if (series && !series->candlestickSets().isEmpty()) {
+ if (m_axisX->type() == QAbstractAxis::AxisTypeBarCategory) {
+ QBarCategoryAxis *axisX = qobject_cast<QBarCategoryAxis *>(m_axisX);
+ QStringList categories;
+ for (int i = 0; i < series->candlestickSets().count(); ++i)
+ categories.append(QString::number(i));
+ axisX->setCategories(categories);
+ } else { // QAbstractAxis::AxisTypeDateTime || QAbstractAxis::AxisTypeValue
+ qreal msInMonth = 31.0 * 24.0 * 60.0 * 60.0 * 1000.0;
+ qreal min = series->candlestickSets().first()->timestamp() - msInMonth;
+ qreal max = series->candlestickSets().last()->timestamp() + msInMonth;
+ QDateTime minDateTime = QDateTime::fromMSecsSinceEpoch(min);
+ QDateTime maxDateTime = QDateTime::fromMSecsSinceEpoch(max);
+
+ if (m_axisX->type() == QAbstractAxis::AxisTypeDateTime)
+ m_axisX->setRange(minDateTime, maxDateTime);
+ else
+ m_axisX->setRange(min, max);
+ }
+ }
+
+ m_axisY = m_chart->axes(Qt::Vertical).first();
+ m_axisY->setMax(15);
+ m_axisY->setMin(0);
+}
+
+void MainWidget::addSeries()
+{
+ if (m_chart->series().count() > 9) {
+ qDebug() << "Maximum series count is 10";
+ return;
+ }
+
+ QCandlestickSeries *series = new QCandlestickSeries();
+ series->setName(QStringLiteral("S%1").arg(m_chart->series().count() + 1));
+ series->setMaximumColumnWidth(m_maximumColumnWidth);
+ series->setMinimumColumnWidth(m_minimumColumnWidth);
+ series->setBodyOutlineVisible(m_bodyOutlineVisible);
+ series->setBodyWidth(m_bodyWidth);
+ series->setCapsVisible(m_capsVisible);
+ series->setCapsWidth(m_capsWidth);
+
+ if (m_chart->series().isEmpty()) {
+ if (m_customIncreasingColor)
+ series->setIncreasingColor(QColor(Qt::green));
+ if (m_customDecreasingColor)
+ series->setDecreasingColor(QColor(Qt::red));
+
+ for (int month = 1; month <= 12; ++month) {
+ QDateTime dateTime;
+ dateTime.setDate(QDate(QDateTime::currentDateTime().date().year(), month, 1));
+ dateTime.setTime(QTime(12, 34, 56, 789));
+
+ QCandlestickSet *set = randomSet(dateTime.toMSecsSinceEpoch());
+ series->append(set);
+ }
+ } else {
+ QCandlestickSeries *s = qobject_cast<QCandlestickSeries *>(m_chart->series().at(0));
+ for (int i = 0; i < s->candlestickSets().count(); ++i) {
+ QCandlestickSet *set = randomSet(s->candlestickSets().at(i)->timestamp());
+ series->append(set);
+ }
+ }
+
+ m_chart->addSeries(series);
+
+ updateAxes();
+ if (!series->attachedAxes().contains(m_axisX))
+ series->attachAxis(m_axisX);
+ if (!series->attachedAxes().contains(m_axisY))
+ series->attachAxis(m_axisY);
+}
+
+void MainWidget::removeSeries()
+{
+ if (m_chart->series().isEmpty()) {
+ qDebug() << "Create a series first";
+ return;
+ }
+
+ if (m_chart->series().count() == 1)
+ detachModelMapper();
+
+ QCandlestickSeries *series = qobject_cast<QCandlestickSeries *>(m_chart->series().last());
+ m_chart->removeSeries(series);
+ delete series;
+ series = nullptr;
+}
+
+void MainWidget::removeAllSeries()
+{
+ if (m_chart->series().isEmpty()) {
+ qDebug() << "Create a series first";
+ return;
+ }
+
+ detachModelMapper();
+
+ m_chart->removeAllSeries();
+}
+
+void MainWidget::addSet()
+{
+ if (m_chart->series().isEmpty()) {
+ qDebug() << "Create a series first";
+ return;
+ }
+
+ foreach (QAbstractSeries *s, m_chart->series()) {
+ QCandlestickSeries *series = qobject_cast<QCandlestickSeries *>(s);
+
+ QDateTime dateTime;
+ if (series->count()) {
+ dateTime.setMSecsSinceEpoch(series->candlestickSets().last()->timestamp());
+ dateTime = dateTime.addMonths(1);
+ } else {
+ dateTime.setDate(QDate(QDateTime::currentDateTime().date().year(), 1, 1));
+ dateTime.setTime(QTime(12, 34, 56, 789));
+ }
+
+ QCandlestickSet *set = randomSet(dateTime.toMSecsSinceEpoch());
+ series->append(set);
+ }
+
+ updateAxes();
+}
+
+void MainWidget::insertSet()
+{
+ if (m_chart->series().isEmpty()) {
+ qDebug() << "Create a series first";
+ return;
+ }
+
+ foreach (QAbstractSeries *s, m_chart->series()) {
+ QCandlestickSeries *series = qobject_cast<QCandlestickSeries *>(s);
+
+ QDateTime dateTime;
+ if (series->count()) {
+ dateTime.setMSecsSinceEpoch(series->candlestickSets().first()->timestamp());
+ dateTime = dateTime.addMonths(-1);
+ } else {
+ dateTime.setDate(QDate(QDateTime::currentDateTime().date().year(), 1, 1));
+ dateTime.setTime(QTime(12, 34, 56, 789));
+ }
+
+ QCandlestickSet *set = randomSet(dateTime.toMSecsSinceEpoch());
+ series->insert(0, set);
+ }
+
+ updateAxes();
+}
+
+void MainWidget::removeSet()
+{
+ if (m_chart->series().isEmpty()) {
+ qDebug() << "Create a series first";
+ return;
+ }
+
+ foreach (QAbstractSeries *s, m_chart->series()) {
+ QCandlestickSeries *series = qobject_cast<QCandlestickSeries *>(s);
+ if (series->candlestickSets().isEmpty())
+ qDebug() << "Create a set first";
+ else
+ series->remove(series->candlestickSets().last());
+ }
+
+ updateAxes();
+}
+
+void MainWidget::removeAllSets()
+{
+ if (m_chart->series().isEmpty()) {
+ qDebug() << "Create a series first";
+ return;
+ }
+
+ foreach (QAbstractSeries *s, m_chart->series()) {
+ QCandlestickSeries *series = qobject_cast<QCandlestickSeries *>(s);
+ if (series->candlestickSets().isEmpty())
+ qDebug() << "Create a set first";
+ else
+ series->clear();
+ }
+
+ updateAxes();
+}
+
+void MainWidget::changeMaximumColumnWidth(double width)
+{
+ m_maximumColumnWidth = width;
+ foreach (QAbstractSeries *s, m_chart->series()) {
+ QCandlestickSeries *series = qobject_cast<QCandlestickSeries *>(s);
+ series->setMaximumColumnWidth(m_maximumColumnWidth);
+ }
+}
+
+void MainWidget::changeMinimumColumnWidth(double width)
+{
+ m_minimumColumnWidth = width;
+ foreach (QAbstractSeries *s, m_chart->series()) {
+ QCandlestickSeries *series = qobject_cast<QCandlestickSeries *>(s);
+ series->setMinimumColumnWidth(m_minimumColumnWidth);
+ }
+}
+
+void MainWidget::bodyOutlineVisibleToggled(bool visible)
+{
+ m_bodyOutlineVisible = visible;
+ foreach (QAbstractSeries *s, m_chart->series()) {
+ QCandlestickSeries *series = qobject_cast<QCandlestickSeries *>(s);
+ series->setBodyOutlineVisible(m_bodyOutlineVisible);
+ }
+}
+
+void MainWidget::capsVisibleToggled(bool visible)
+{
+ m_capsVisible = visible;
+ foreach (QAbstractSeries *s, m_chart->series()) {
+ QCandlestickSeries *series = qobject_cast<QCandlestickSeries *>(s);
+ series->setCapsVisible(m_capsVisible);
+ }
+}
+
+void MainWidget::changeBodyWidth(double width)
+{
+ m_bodyWidth = width;
+ foreach (QAbstractSeries *s, m_chart->series()) {
+ QCandlestickSeries *series = qobject_cast<QCandlestickSeries *>(s);
+ series->setBodyWidth(m_bodyWidth);
+ }
+}
+
+void MainWidget::changeCapsWidth(double width)
+{
+ m_capsWidth = width;
+ foreach (QAbstractSeries *s, m_chart->series()) {
+ QCandlestickSeries *series = qobject_cast<QCandlestickSeries *>(s);
+ series->setCapsWidth(m_capsWidth);
+ }
+}
+
+void MainWidget::customIncreasingColorToggled(bool custom)
+{
+ m_customIncreasingColor = custom;
+
+ if (m_chart->series().isEmpty())
+ return;
+
+ QCandlestickSeries *series = qobject_cast<QCandlestickSeries *>(m_chart->series().at(0));
+ if (series) {
+ QColor color = m_customIncreasingColor ? QColor(Qt::green) : QColor();
+ series->setIncreasingColor(color);
+ }
+}
+
+void MainWidget::customDecreasingColorToggled(bool custom)
+{
+ m_customDecreasingColor = custom;
+
+ if (m_chart->series().isEmpty())
+ return;
+
+ QCandlestickSeries *series = qobject_cast<QCandlestickSeries *>(m_chart->series().at(0));
+ if (series) {
+ QColor color = m_customDecreasingColor ? QColor(Qt::red) : QColor();
+ series->setDecreasingColor(color);
+ }
+}
+
+void MainWidget::antialiasingToggled(bool enabled)
+{
+ m_chartView->setRenderHint(QPainter::Antialiasing, enabled);
+}
+
+void MainWidget::animationToggled(bool enabled)
+{
+ if (enabled)
+ m_chart->setAnimationOptions(QChart::SeriesAnimations);
+ else
+ m_chart->setAnimationOptions(QChart::NoAnimation);
+}
+
+void MainWidget::legendToggled(bool visible)
+{
+ m_chart->legend()->setVisible(visible);
+ if (visible)
+ m_chart->legend()->setAlignment(Qt::AlignBottom);
+}
+
+void MainWidget::titleToggled(bool visible)
+{
+ if (visible)
+ m_chart->setTitle(QStringLiteral("Candlestick Chart"));
+ else
+ m_chart->setTitle(QString());
+}
+
+void MainWidget::changeChartTheme(int themeIndex)
+{
+ if (themeIndex < QChart::ChartThemeLight || themeIndex > QChart::ChartThemeQt) {
+ qDebug() << "Invalid chart theme index:" << themeIndex;
+ return;
+ }
+
+ m_chart->setTheme((QChart::ChartTheme)(themeIndex));
+}
+
+void MainWidget::changeAxisX(int axisXIndex)
+{
+ if (m_axisX) {
+ m_chart->removeAxis(m_axisX);
+ delete m_axisX;
+ }
+
+ switch (axisXIndex) {
+ case 0:
+ m_axisX = new QBarCategoryAxis();
+ break;
+ case 1:
+ m_axisX = new QDateTimeAxis();
+ break;
+ case 2:
+ m_axisX = new QValueAxis();
+ break;
+ default:
+ qDebug() << "Invalid axis x index:" << axisXIndex;
+ return;
+ }
+
+ m_chart->addAxis(m_axisX, Qt::AlignBottom);
+
+ updateAxes();
+
+ foreach (QAbstractSeries *series, m_chart->series())
+ series->attachAxis(m_axisX);
+}
+
+void MainWidget::attachModelMapper()
+{
+ if (m_hModelMapper->series()) {
+ qDebug() << "Model mapper is already attached";
+ return;
+ }
+
+ if (m_chart->series().isEmpty())
+ addSeries();
+
+ QCandlestickSeries *series = qobject_cast<QCandlestickSeries *>(m_chart->series().at(0));
+ Q_ASSERT(series);
+ series->setName(QStringLiteral("SWMM")); // Series With Model Mapper
+
+ CustomTableModel *model = qobject_cast<CustomTableModel *>(m_hModelMapper->model());
+ foreach (QCandlestickSet *set, series->candlestickSets())
+ model->addRow(set);
+
+ m_hModelMapper->setFirstCandlestickSetRow(0);
+ m_hModelMapper->setLastCandlestickSetRow(model->rowCount() - 1);
+ m_hModelMapper->setSeries(series);
+}
+
+void MainWidget::detachModelMapper()
+{
+ if (!m_hModelMapper->series())
+ return;
+
+ QCandlestickSeries *series = qobject_cast<QCandlestickSeries *>(m_hModelMapper->series());
+ Q_ASSERT(series);
+ series->setName(QStringLiteral("S1"));
+
+ m_hModelMapper->setSeries(nullptr);
+ m_hModelMapper->setFirstCandlestickSetRow(-1);
+ m_hModelMapper->setLastCandlestickSetRow(-1);
+
+ CustomTableModel *model = qobject_cast<CustomTableModel *>(m_hModelMapper->model());
+ model->clearRows();
+}
diff --git a/tests/manual/candlesticktester/mainwidget.h b/tests/manual/candlesticktester/mainwidget.h
new file mode 100644
index 00000000..4044515a
--- /dev/null
+++ b/tests/manual/candlesticktester/mainwidget.h
@@ -0,0 +1,108 @@
+/****************************************************************************
+**
+** 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$
+**
+****************************************************************************/
+
+#ifndef MAINWIDGET_H
+#define MAINWIDGET_H
+
+#include <QtCharts/QChartView>
+#include <QtWidgets/QWidget>
+
+QT_BEGIN_NAMESPACE
+class QGridLayout;
+QT_END_NAMESPACE
+
+QT_CHARTS_BEGIN_NAMESPACE
+class QCandlestickSet;
+class QHCandlestickModelMapper;
+QT_CHARTS_END_NAMESPACE
+
+QT_CHARTS_USE_NAMESPACE
+
+class MainWidget : public QWidget
+{
+ Q_OBJECT
+
+public:
+ explicit MainWidget(QWidget *parent = nullptr);
+ ~MainWidget();
+
+private:
+ QGridLayout *createSeriesControlsLayout();
+ QGridLayout *createSetsControlsLayout();
+ QGridLayout *createCandlestickControlsLayout();
+ QGridLayout *createMiscellaneousControlsLayout();
+ QGridLayout *createModelMapperControlsLayout();
+
+ qreal randomValue(int min, int max) const;
+ QCandlestickSet *randomSet(qreal timestamp);
+
+ void updateAxes();
+
+private slots:
+ void addSeries();
+ void removeSeries();
+ void removeAllSeries();
+ void addSet();
+ void insertSet();
+ void removeSet();
+ void removeAllSets();
+ void changeMaximumColumnWidth(double width);
+ void changeMinimumColumnWidth(double width);
+ void bodyOutlineVisibleToggled(bool visible);
+ void capsVisibleToggled(bool visible);
+ void changeBodyWidth(double width);
+ void changeCapsWidth(double width);
+ void customIncreasingColorToggled(bool custom);
+ void customDecreasingColorToggled(bool custom);
+ void antialiasingToggled(bool enabled);
+ void animationToggled(bool enabled);
+ void legendToggled(bool visible);
+ void titleToggled(bool visible);
+ void changeChartTheme(int themeIndex);
+ void changeAxisX(int axisXIndex);
+ void attachModelMapper();
+ void detachModelMapper();
+
+private:
+ QChart *m_chart;
+ QChartView *m_chartView;
+ QAbstractAxis *m_axisX;
+ QAbstractAxis *m_axisY;
+ qreal m_maximumColumnWidth;
+ qreal m_minimumColumnWidth;
+ bool m_bodyOutlineVisible;
+ bool m_capsVisible;
+ qreal m_bodyWidth;
+ qreal m_capsWidth;
+ bool m_customIncreasingColor;
+ bool m_customDecreasingColor;
+ QHCandlestickModelMapper *m_hModelMapper;
+};
+
+#endif // MAINWIDGET_H
diff --git a/tests/manual/manual.pro b/tests/manual/manual.pro
index 25545aeb..0e02e8c2 100644
--- a/tests/manual/manual.pro
+++ b/tests/manual/manual.pro
@@ -2,7 +2,8 @@ TEMPLATE = subdirs
SUBDIRS += \
presenterchart \
polarcharttest \
- boxplottester
+ boxplottester \
+ candlesticktester
contains(QT_CONFIG, opengl) {
SUBDIRS += chartwidgettest \