1/****************************************************************************
2**
3** Copyright (C) 2016 The Qt Company Ltd.
4** Contact: https://www.qt.io/licensing/
5**
6** This file is part of the Qt Charts module of the Qt Toolkit.
7**
8** $QT_BEGIN_LICENSE:GPL$
9** Commercial License Usage
10** Licensees holding valid commercial Qt licenses may use this file in
11** accordance with the commercial license agreement provided with the
12** Software or, alternatively, in accordance with the terms contained in
13** a written agreement between you and The Qt Company. For licensing terms
14** and conditions see https://www.qt.io/terms-conditions. For further
15** information use the contact form at https://www.qt.io/contact-us.
16**
17** GNU General Public License Usage
18** Alternatively, this file may be used under the terms of the GNU
19** General Public License version 3 or (at your option) any later version
20** approved by the KDE Free Qt Foundation. The licenses are as published by
21** the Free Software Foundation and appearing in the file LICENSE.GPL3
22** included in the packaging of this file. Please review the following
23** information to ensure the GNU General Public License requirements will
24** be met: https://www.gnu.org/licenses/gpl-3.0.html.
25**
26** $QT_END_LICENSE$
27**
28****************************************************************************/
29
30#include <QtCharts/QCandlestickSeries>
31#include <QtCharts/QCandlestickSet>
32#include <QtCharts/QChartView>
33#include <QtTest/QtTest>
34#include "tst_definitions.h"
35
36QT_CHARTS_USE_NAMESPACE
37
38Q_DECLARE_METATYPE(QCandlestickSet *)
39Q_DECLARE_METATYPE(QList<QCandlestickSet *>)
40
41class tst_QCandlestickSeries : public QObject
42{
43 Q_OBJECT
44
45public Q_SLOTS:
46 void initTestCase();
47 void cleanupTestCase();
48 void init();
49 void cleanup();
50
51private Q_SLOTS:
52 void qCandlestickSeries();
53 void append();
54 void remove();
55 void appendList();
56 void removeList();
57 void insert();
58 void take();
59 void clear();
60 void sets();
61 void count();
62 void type();
63 void maximumColumnWidth_data();
64 void maximumColumnWidth();
65 void minimumColumnWidth_data();
66 void minimumColumnWidth();
67 void bodyWidth_data();
68 void bodyWidth();
69 void bodyOutlineVisible();
70 void capsWidth_data();
71 void capsWidth();
72 void capsVisible();
73 void increasingColor();
74 void decreasingColor();
75 void brush();
76 void pen();
77 void mouseClicked();
78 void mouseHovered();
79 void mousePressed();
80 void mouseReleased();
81 void mouseDoubleClicked();
82
83private:
84 QPointer<QCandlestickSeries> m_series;
85 struct SetList : QList<QPointer<QCandlestickSet>> {
86 operator QList<QCandlestickSet *> () const {
87 QList<QCandlestickSet *> list;
88 for (int i = 0; i < count(); ++i)
89 list.append(t: at(i));
90 return list;
91 }
92 }; SetList m_sets;
93};
94
95void tst_QCandlestickSeries::initTestCase()
96{
97 qRegisterMetaType<QCandlestickSet *>(typeName: "QCandlestickSet *");
98 qRegisterMetaType<QList<QCandlestickSet *>>(typeName: "QList<QCandlestickSet *>");
99}
100
101void tst_QCandlestickSeries::cleanupTestCase()
102{
103 QTest::qWait(ms: 1); // Allow final deleteLaters to run
104}
105
106void tst_QCandlestickSeries::init()
107{
108 m_series = new QCandlestickSeries();
109 m_series->setMaximumColumnWidth(5432.1);
110 m_series->setMinimumColumnWidth(2.0);
111 m_series->setBodyWidth(0.99);
112 m_series->setCapsWidth(0.99);
113
114 for (int i = 0; i < 5; ++i) {
115 qreal timestamp = QDateTime::currentMSecsSinceEpoch() + i * 1000000;
116
117 QCandlestickSet *set = new QCandlestickSet(timestamp);
118 set->setOpen(4);
119 set->setHigh(4);
120 set->setLow(1);
121 set->setClose(1);
122
123 m_sets.append(t: set);
124 }
125}
126
127void tst_QCandlestickSeries::cleanup()
128{
129 delete m_series;
130 qDeleteAll(c: m_sets);
131 m_sets.clear();
132}
133
134void tst_QCandlestickSeries::qCandlestickSeries()
135{
136 QCandlestickSeries *series = new QCandlestickSeries();
137
138 QVERIFY(series != nullptr);
139
140 delete series;
141 series = nullptr;
142}
143
144void tst_QCandlestickSeries::append()
145{
146 QCOMPARE(m_series->count(), 0);
147
148 // Try adding set
149 QCandlestickSet *set1 = new QCandlestickSet(1234.0);
150 QVERIFY(m_series->append(set1));
151 QCOMPARE(m_series->count(), 1);
152
153 // Try adding another set
154 QCandlestickSet *set2 = new QCandlestickSet(2345.0);
155 QVERIFY(m_series->append(set2));
156 QCOMPARE(m_series->count(), 2);
157
158 // Try adding same set again
159 QVERIFY(!m_series->append(set2));
160 QCOMPARE(m_series->count(), 2);
161
162 // Try adding null set
163 QVERIFY(!m_series->append(nullptr));
164 QCOMPARE(m_series->count(), 2);
165}
166
167void tst_QCandlestickSeries::remove()
168{
169 m_series->append(sets: m_sets);
170 QCOMPARE(m_series->count(), m_sets.count());
171
172 // Try to remove null pointer (should not remove, should not crash)
173 QVERIFY(!m_series->remove(nullptr));
174 QCOMPARE(m_series->count(), m_sets.count());
175
176 // Try to remove invalid pointer (should not remove, should not crash)
177 QVERIFY(!m_series->remove((QCandlestickSet *)(m_sets.at(0) + 1)));
178 QCOMPARE(m_series->count(), m_sets.count());
179
180 // Remove some sets
181 const int removeCount = 3;
182 for (int i = 0; i < removeCount; ++i) {
183 QVERIFY(m_series->remove(m_sets.at(i)));
184 QVERIFY(!m_sets.at(i));
185 }
186 QCOMPARE(m_series->count(), m_sets.count() - removeCount);
187
188 for (int i = removeCount; i < m_sets.count(); ++i)
189 QCOMPARE(m_series->sets().at(i - removeCount), m_sets.at(i));
190
191 // Try removing all sets again (should be ok, even if some sets have already been removed)
192 for (int i = 0; i < m_sets.count(); ++i) {
193 m_series->remove(set: m_sets.at(i));
194 QVERIFY(!m_sets.at(i));
195 }
196 QCOMPARE(m_series->count(), 0);
197}
198
199void tst_QCandlestickSeries::appendList()
200{
201 QCOMPARE(m_series->count(), 0);
202
203 // Append new sets (should succeed, count should match the count of sets)
204 QVERIFY(m_series->append(m_sets));
205 QCOMPARE(m_series->count(), m_series->count());
206
207 // Append same sets again (should fail, count should remain same)
208 QVERIFY(!m_series->append(m_sets));
209 QCOMPARE(m_series->count(), m_series->count());
210
211 // Try append empty list (should succeed, but count should remain same)
212 QList<QCandlestickSet *> invalidList;
213 QVERIFY(m_series->append(invalidList));
214 QCOMPARE(m_series->count(), m_sets.count());
215
216 // Try append list with one new and one existing set (should fail, count remains same)
217 invalidList.append(t: new QCandlestickSet());
218 invalidList.append(t: m_sets.at(i: 0));
219 QVERIFY(!m_series->append(invalidList));
220 QCOMPARE(m_series->count(), m_sets.count());
221 delete invalidList.at(i: 0);
222 invalidList.clear();
223
224 // Try append list with null pointers (should fail, count remains same)
225 QVERIFY(invalidList.isEmpty());
226 invalidList.append(t: nullptr);
227 invalidList.append(t: nullptr);
228 invalidList.append(t: nullptr);
229 QVERIFY(!m_series->append(invalidList));
230 QCOMPARE(m_series->count(), m_sets.count());
231}
232
233void tst_QCandlestickSeries::removeList()
234{
235 m_series->append(sets: m_sets);
236 QCOMPARE(m_series->count(), m_sets.count());
237
238 // Try remove empty list (should fail, but count should remain same)
239 QList<QCandlestickSet *> invalidList;
240 QVERIFY(!m_series->remove(invalidList));
241 QCOMPARE(m_series->count(), m_sets.count());
242
243 // Try remove list with one new and one existing set (should fail, count remains same)
244 invalidList.append(t: new QCandlestickSet());
245 invalidList.append(t: m_sets.at(i: 0));
246 QVERIFY(!m_series->remove(invalidList));
247 QCOMPARE(m_series->count(), m_sets.count());
248 delete invalidList.at(i: 0);
249 invalidList.clear();
250
251 // Try remove list with null pointers (should fail, count remains same)
252 QVERIFY(invalidList.isEmpty());
253 invalidList.append(t: nullptr);
254 invalidList.append(t: nullptr);
255 invalidList.append(t: nullptr);
256 QVERIFY(!m_series->remove(invalidList));
257 QCOMPARE(m_series->count(), m_sets.count());
258
259 // Remove all sets (should succeed, count should be zero)
260 QVERIFY(m_series->remove(m_sets));
261 QCOMPARE(m_series->count(), 0);
262
263 // Remove same sets again (should fail, count should remain zero)
264 QVERIFY(!m_series->remove(m_sets));
265 QCOMPARE(m_series->count(), 0);
266}
267
268void tst_QCandlestickSeries::insert()
269{
270 QCOMPARE(m_series->count(), 0);
271
272 QSignalSpy countSpy(m_series, SIGNAL(countChanged()));
273 QSignalSpy addedSpy(m_series, SIGNAL(candlestickSetsAdded(QList<QCandlestickSet *>)));
274
275 for (int i = 0; i < m_sets.count(); ++i) {
276 QCandlestickSet *set = m_sets.at(i);
277 QVERIFY(m_series->insert(0, set));
278 QCOMPARE(m_series->count(), i + 1);
279 QTRY_COMPARE(countSpy.count(), i + 1);
280 QTRY_COMPARE(addedSpy.count(), i + 1);
281
282 QList<QVariant> args = addedSpy.value(i);
283 QCOMPARE(args.count(), 1);
284 QList<QCandlestickSet *> sets = qvariant_cast<QList<QCandlestickSet *>>(v: args.at(i: 0));
285 QCOMPARE(sets.count(), 1);
286 QCOMPARE(sets.first(), set);
287 }
288}
289
290void tst_QCandlestickSeries::take()
291{
292 m_series->append(sets: m_sets);
293 QCOMPARE(m_series->count(), m_sets.count());
294
295 QSignalSpy countSpy(m_series, SIGNAL(countChanged()));
296 QSignalSpy removedSpy(m_series, SIGNAL(candlestickSetsRemoved(QList<QCandlestickSet *>)));
297
298 for (int i = 0; i < m_sets.count(); ++i) {
299 QCandlestickSet *set = m_sets.at(i);
300 QVERIFY(m_series->take(set));
301 QCOMPARE(m_series->count(), m_sets.count() - i - 1);
302 QTRY_COMPARE(countSpy.count(), i + 1);
303 QTRY_COMPARE(removedSpy.count(), i + 1);
304
305 QList<QVariant> args = removedSpy.value(i);
306 QCOMPARE(args.count(), 1);
307 QList<QCandlestickSet *> sets = qvariant_cast<QList<QCandlestickSet *>>(v: args.at(i: 0));
308 QCOMPARE(sets.count(), 1);
309 QCOMPARE(sets.first(), set);
310 }
311}
312
313void tst_QCandlestickSeries::clear()
314{
315 m_series->append(sets: m_sets);
316 QCOMPARE(m_series->count(), m_sets.count());
317
318 m_series->clear();
319 QCOMPARE(m_series->count(), 0);
320}
321
322void tst_QCandlestickSeries::sets()
323{
324 m_series->append(sets: m_sets);
325 QCOMPARE(m_series->sets(), m_sets);
326
327 for (int i = 0; i < m_sets.count(); ++i)
328 QCOMPARE(m_series->sets().at(i), m_sets.at(i));
329
330 m_series->clear();
331 QCOMPARE(m_series->sets(), QList<QCandlestickSet *>());
332}
333
334void tst_QCandlestickSeries::count()
335{
336 m_series->append(sets: m_sets);
337 QCOMPARE(m_series->count(), m_sets.count());
338 QCOMPARE(m_series->count(), m_series->sets().count());
339}
340
341void tst_QCandlestickSeries::type()
342{
343 QCOMPARE(m_series->type(), QAbstractSeries::SeriesTypeCandlestick);
344}
345
346void tst_QCandlestickSeries::maximumColumnWidth_data()
347{
348 QTest::addColumn<qreal>(name: "maximumColumnWidth");
349 QTest::addColumn<qreal>(name: "expectedMaximumColumnWidth");
350
351 QTest::newRow(dataTag: "maximum column width less than -1.0") << -3.0 << -1.0;
352 QTest::newRow(dataTag: "maximum column equals to -1.0") << -1.0 << -1.0;
353 QTest::newRow(dataTag: "maximum column width greater than -1.0, but less than zero") << -0.5 << -1.0;
354 QTest::newRow(dataTag: "maximum column width equals zero") << 0.0 << 0.0;
355 QTest::newRow(dataTag: "maximum column width greater than zero") << 1.0 << 1.0;
356 QTest::newRow(dataTag: "maximum column width contains a fractional part") << 3.4 << 3.4;
357}
358
359void tst_QCandlestickSeries::maximumColumnWidth()
360{
361 QFETCH(qreal, maximumColumnWidth);
362 QFETCH(qreal, expectedMaximumColumnWidth);
363
364 QSignalSpy spy(m_series, SIGNAL(maximumColumnWidthChanged()));
365
366 m_series->setMaximumColumnWidth(maximumColumnWidth);
367 QCOMPARE(m_series->maximumColumnWidth(), expectedMaximumColumnWidth);
368 QCOMPARE(spy.count(), 1);
369
370 // Try set same maximum column width
371 m_series->setMaximumColumnWidth(expectedMaximumColumnWidth);
372 QCOMPARE(m_series->maximumColumnWidth(), expectedMaximumColumnWidth);
373 QCOMPARE(spy.count(), 1);
374}
375
376void tst_QCandlestickSeries::minimumColumnWidth_data()
377{
378 QTest::addColumn<qreal>(name: "minimumColumnWidth");
379 QTest::addColumn<qreal>(name: "expectedMinimumColumnWidth");
380
381 QTest::newRow(dataTag: "minimum column width less than -1.0") << -3.0 << -1.0;
382 QTest::newRow(dataTag: "minimum column equals to -1.0") << -1.0 << -1.0;
383 QTest::newRow(dataTag: "minimum column width greater than -1.0, but less than zero") << -0.5 << -1.0;
384 QTest::newRow(dataTag: "minimum column width equals zero") << 0.0 << 0.0;
385 QTest::newRow(dataTag: "minimum column width greater than zero") << 1.0 << 1.0;
386 QTest::newRow(dataTag: "minimum column width contains a fractional part") << 3.4 << 3.4;
387}
388
389void tst_QCandlestickSeries::minimumColumnWidth()
390{
391 QFETCH(qreal, minimumColumnWidth);
392 QFETCH(qreal, expectedMinimumColumnWidth);
393
394 QSignalSpy spy(m_series, SIGNAL(minimumColumnWidthChanged()));
395
396 m_series->setMinimumColumnWidth(minimumColumnWidth);
397 QCOMPARE(m_series->minimumColumnWidth(), expectedMinimumColumnWidth);
398 QCOMPARE(spy.count(), 1);
399
400 // Try set same minimum column width
401 m_series->setMinimumColumnWidth(expectedMinimumColumnWidth);
402 QCOMPARE(m_series->minimumColumnWidth(), expectedMinimumColumnWidth);
403 QCOMPARE(spy.count(), 1);
404}
405
406void tst_QCandlestickSeries::bodyWidth_data()
407{
408 QTest::addColumn<qreal>(name: "bodyWidth");
409 QTest::addColumn<qreal>(name: "expectedBodyWidth");
410
411 QTest::newRow(dataTag: "body width less than zero") << -1.0 << 0.0;
412 QTest::newRow(dataTag: "body width equals zero") << 0.0 << 0.0;
413 QTest::newRow(dataTag: "body width greater than zero and less than one") << 0.5 << 0.5;
414 QTest::newRow(dataTag: "body width equals one") << 1.0 << 1.0;
415 QTest::newRow(dataTag: "body width greater than one") << 2.0 << 1.0;
416}
417
418void tst_QCandlestickSeries::bodyWidth()
419{
420 QFETCH(qreal, bodyWidth);
421 QFETCH(qreal, expectedBodyWidth);
422
423 QSignalSpy spy(m_series, SIGNAL(bodyWidthChanged()));
424
425 m_series->setBodyWidth(bodyWidth);
426 QCOMPARE(m_series->bodyWidth(), expectedBodyWidth);
427 QCOMPARE(spy.count(), 1);
428
429 // Try set same body width
430 m_series->setBodyWidth(bodyWidth);
431 QCOMPARE(m_series->bodyWidth(), expectedBodyWidth);
432 QCOMPARE(spy.count(), 1);
433}
434
435void tst_QCandlestickSeries::bodyOutlineVisible()
436{
437 QSignalSpy spy(m_series, SIGNAL(bodyOutlineVisibilityChanged()));
438
439 bool visible = !m_series->bodyOutlineVisible();
440 m_series->setBodyOutlineVisible(visible);
441 QCOMPARE(m_series->bodyOutlineVisible(), visible);
442 QCOMPARE(spy.count(), 1);
443
444 // Try set same body outline visibility
445 m_series->setBodyOutlineVisible(visible);
446 QCOMPARE(m_series->bodyOutlineVisible(), visible);
447 QCOMPARE(spy.count(), 1);
448}
449
450void tst_QCandlestickSeries::capsWidth_data()
451{
452 QTest::addColumn<qreal>(name: "capsWidth");
453 QTest::addColumn<qreal>(name: "expectedCapsWidth");
454
455 QTest::newRow(dataTag: "caps width less than zero") << -1.0 << 0.0;
456 QTest::newRow(dataTag: "caps width equals zero") << 0.0 << 0.0;
457 QTest::newRow(dataTag: "caps width greater than zero and less than one") << 0.5 << 0.5;
458 QTest::newRow(dataTag: "caps width equals one") << 1.0 << 1.0;
459 QTest::newRow(dataTag: "caps width greater than one") << 2.0 << 1.0;
460}
461
462void tst_QCandlestickSeries::capsWidth()
463{
464 QFETCH(qreal, capsWidth);
465 QFETCH(qreal, expectedCapsWidth);
466
467 QSignalSpy spy(m_series, SIGNAL(capsWidthChanged()));
468
469 m_series->setCapsWidth(capsWidth);
470 QCOMPARE(m_series->capsWidth(), expectedCapsWidth);
471 QCOMPARE(spy.count(), 1);
472
473 // Try set same caps width
474 m_series->setCapsWidth(capsWidth);
475 QCOMPARE(m_series->capsWidth(), expectedCapsWidth);
476 QCOMPARE(spy.count(), 1);
477}
478
479void tst_QCandlestickSeries::capsVisible()
480{
481 QSignalSpy spy(m_series, SIGNAL(capsVisibilityChanged()));
482
483 bool visible = !m_series->capsVisible();
484 m_series->setCapsVisible(visible);
485 QCOMPARE(m_series->capsVisible(), visible);
486 QCOMPARE(spy.count(), 1);
487
488 // Try set same caps visibility
489 m_series->setCapsVisible(visible);
490 QCOMPARE(m_series->capsVisible(), visible);
491 QCOMPARE(spy.count(), 1);
492}
493
494void tst_QCandlestickSeries::increasingColor()
495{
496 QSignalSpy spy(m_series, SIGNAL(increasingColorChanged()));
497
498 // Try set new increasing color
499 QColor newColor(200, 200, 200, 200);
500 m_series->setIncreasingColor(newColor);
501 QCOMPARE(m_series->increasingColor(), newColor);
502 QCOMPARE(spy.count(), 1);
503
504 // Try set same increasing color again
505 m_series->setIncreasingColor(newColor);
506 QCOMPARE(m_series->increasingColor(), newColor);
507 QCOMPARE(spy.count(), 1);
508
509 // Try set invalid increasing color (should change to default color)
510 QColor defaultColor = m_series->brush().color();
511 defaultColor.setAlpha(128);
512 m_series->setIncreasingColor(QColor());
513 QCOMPARE(m_series->increasingColor(), defaultColor);
514 QCOMPARE(spy.count(), 2);
515
516 // Set new brush, increasing color should change accordingly
517 QBrush brush(newColor);
518 defaultColor = brush.color();
519 defaultColor.setAlpha(128);
520 m_series->setBrush(brush);
521 QCOMPARE(m_series->increasingColor(), defaultColor);
522 QCOMPARE(spy.count(), 3);
523}
524
525void tst_QCandlestickSeries::decreasingColor()
526{
527 QSignalSpy spy(m_series, SIGNAL(decreasingColorChanged()));
528
529 // Try set new decreasing color
530 QColor newColor(200, 200, 200, 200);
531 m_series->setDecreasingColor(newColor);
532 QCOMPARE(m_series->decreasingColor(), newColor);
533 QCOMPARE(spy.count(), 1);
534
535 // Try set same decreasing color again
536 m_series->setDecreasingColor(newColor);
537 QCOMPARE(m_series->decreasingColor(), newColor);
538 QCOMPARE(spy.count(), 1);
539
540 // Try set invalid decreasing color (should change to default color)
541 m_series->setDecreasingColor(QColor());
542 QCOMPARE(m_series->decreasingColor(), m_series->brush().color());
543 QCOMPARE(spy.count(), 2);
544
545 // Set new brush, decreasing color should change accordingly
546 m_series->setBrush(QBrush(newColor));
547 QCOMPARE(m_series->decreasingColor(), m_series->brush().color());
548 QCOMPARE(spy.count(), 3);
549}
550
551void tst_QCandlestickSeries::brush()
552{
553 QSignalSpy spy(m_series, SIGNAL(brushChanged()));
554
555 QBrush brush(QColor(128, 128, 128, 128));
556 QColor increasingColor(brush.color());
557 increasingColor.setAlpha(128);
558 QColor decreasingColor(brush.color());
559 m_series->setBrush(brush);
560 QCOMPARE(m_series->brush(), brush);
561 QCOMPARE(m_series->increasingColor(), increasingColor);
562 QCOMPARE(m_series->decreasingColor(), decreasingColor);
563 QCOMPARE(spy.count(), 1);
564
565 // Try set same brush
566 m_series->setBrush(brush);
567 QCOMPARE(m_series->brush(), brush);
568 QCOMPARE(m_series->increasingColor(), increasingColor);
569 QCOMPARE(m_series->decreasingColor(), decreasingColor);
570 QCOMPARE(spy.count(), 1);
571}
572
573void tst_QCandlestickSeries::pen()
574{
575 QSignalSpy spy(m_series, SIGNAL(penChanged()));
576
577 QPen pen(QColor(128, 128, 128, 128));
578 m_series->setPen(pen);
579 QCOMPARE(m_series->pen(), pen);
580 QCOMPARE(spy.count(), 1);
581
582 // Try set same pen
583 m_series->setPen(pen);
584 QCOMPARE(m_series->pen(), pen);
585 QCOMPARE(spy.count(), 1);
586}
587
588void tst_QCandlestickSeries::mouseClicked()
589{
590 SKIP_IF_CANNOT_TEST_MOUSE_EVENTS();
591
592 QVERIFY(m_series->append(m_sets));
593 QCOMPARE(m_series->count(), m_sets.count());
594
595 QCandlestickSet *set1 = m_series->sets().at(i: 1);
596 QCandlestickSet *set2 = m_series->sets().at(i: 2);
597
598 QSignalSpy seriesSpy(m_series, SIGNAL(clicked(QCandlestickSet *)));
599 QSignalSpy setSpy1(set1, SIGNAL(clicked()));
600 QSignalSpy setSpy2(set2, SIGNAL(clicked()));
601
602 QChartView view(new QChart());
603 view.resize(w: 400, h: 300);
604 view.chart()->addSeries(series: m_series);
605 view.chart()->createDefaultAxes();
606 view.show();
607 QVERIFY(QTest::qWaitForWindowExposed(&view));
608
609 // Calculate expected layout for candlesticks
610 QRectF plotArea = view.chart()->plotArea();
611 qreal candlestickWidth = plotArea.width() / m_series->count();
612 qreal candlestickHeight = plotArea.height();
613
614 QMap<QCandlestickSet *, QRectF> layout;
615 layout.insert(akey: set1, avalue: QRectF(plotArea.left() + candlestickWidth * m_sets.indexOf(t: set1),
616 plotArea.top(), candlestickWidth, candlestickHeight));
617 layout.insert(akey: set2, avalue: QRectF(plotArea.left() + candlestickWidth * m_sets.indexOf(t: set2),
618 plotArea.top(), candlestickWidth, candlestickHeight));
619
620 // Click set 1
621 QTest::mouseClick(widget: view.viewport(), button: Qt::LeftButton, stateKey: {}, pos: layout.value(akey: set1).center().toPoint());
622 QCoreApplication::processEvents(flags: QEventLoop::AllEvents, maxtime: 1000);
623
624 QCOMPARE(seriesSpy.count(), 1);
625 QCOMPARE(setSpy1.count(), 1);
626 QCOMPARE(setSpy2.count(), 0);
627
628 QList<QVariant> seriesSpyArgs = seriesSpy.takeFirst();
629 QCOMPARE(seriesSpyArgs.count(), 1);
630 QCOMPARE(qvariant_cast<QCandlestickSet *>(seriesSpyArgs.at(0)), set1);
631 seriesSpyArgs.clear();
632
633 QVERIFY(setSpy1.takeFirst().isEmpty());
634
635 // Click set 2
636 QTest::mouseClick(widget: view.viewport(), button: Qt::LeftButton, stateKey: {}, pos: layout.value(akey: set2).center().toPoint());
637 QCoreApplication::processEvents(flags: QEventLoop::AllEvents, maxtime: 1000);
638
639 QCOMPARE(seriesSpy.count(), 1);
640 QCOMPARE(setSpy1.count(), 0);
641 QCOMPARE(setSpy2.count(), 1);
642
643 seriesSpyArgs = seriesSpy.takeFirst();
644 QCOMPARE(seriesSpyArgs.count(), 1);
645 QCOMPARE(qvariant_cast<QCandlestickSet *>(seriesSpyArgs.at(0)), set2);
646 seriesSpyArgs.clear();
647
648 QVERIFY(setSpy2.takeFirst().isEmpty());
649}
650
651void tst_QCandlestickSeries::mouseHovered()
652{
653 SKIP_IF_CANNOT_TEST_MOUSE_EVENTS();
654 SKIP_IF_FLAKY_MOUSE_MOVE();
655
656 QVERIFY(m_series->append(m_sets));
657 QCOMPARE(m_series->count(), m_sets.count());
658
659 QCandlestickSet *set1 = m_series->sets().at(i: 1);
660 QCandlestickSet *set2 = m_series->sets().at(i: 2);
661
662 QSignalSpy seriesSpy(m_series, SIGNAL(hovered(bool, QCandlestickSet *)));
663 QSignalSpy setSpy1(set1, SIGNAL(hovered(bool)));
664 QSignalSpy setSpy2(set2, SIGNAL(hovered(bool)));
665
666 QChartView view(new QChart());
667 view.resize(w: 400, h: 300);
668 view.chart()->addSeries(series: m_series);
669 view.chart()->createDefaultAxes();
670 view.show();
671 QVERIFY(QTest::qWaitForWindowExposed(&view));
672
673 // This is hack since view does not get events otherwise
674 view.setMouseTracking(true);
675
676 // Calculate expected layout for candlesticks
677 QRectF plotArea = view.chart()->plotArea();
678 qreal candlestickWidth = plotArea.width() / m_series->count();
679 qreal candlestickHeight = plotArea.height();
680
681 QMap<QCandlestickSet *, QRectF> layout;
682 layout.insert(akey: set1, avalue: QRectF(plotArea.left() + candlestickWidth * m_sets.indexOf(t: set1),
683 plotArea.top(), candlestickWidth, candlestickHeight));
684 layout.insert(akey: set2, avalue: QRectF(plotArea.left() + candlestickWidth * m_sets.indexOf(t: set2),
685 plotArea.top(), candlestickWidth, candlestickHeight));
686
687 // Move mouse to left border
688 QTest::mouseMove(widget: view.viewport(), pos: QPoint(0, layout.value(akey: set1).center().y()));
689 QCoreApplication::processEvents(flags: QEventLoop::AllEvents, maxtime: 1000);
690
691 QCOMPARE(seriesSpy.count(), 0);
692 QCOMPARE(setSpy1.count(), 0);
693 QCOMPARE(setSpy2.count(), 0);
694
695 // Move mouse on top of set 1
696 QTest::mouseMove(widget: view.viewport(), pos: layout.value(akey: set1).center().toPoint());
697 QCoreApplication::processEvents(flags: QEventLoop::AllEvents, maxtime: 1000);
698
699 QCOMPARE(seriesSpy.count(), 1);
700 QCOMPARE(setSpy1.count(), 1);
701 QCOMPARE(setSpy2.count(), 0);
702
703 QList<QVariant> seriesSpyArgs = seriesSpy.takeFirst();
704 QCOMPARE(qvariant_cast<QCandlestickSet *>(seriesSpyArgs.at(1)), set1);
705 QCOMPARE(seriesSpyArgs.at(0).type(), QVariant::Bool);
706 QCOMPARE(seriesSpyArgs.at(0).toBool(), true);
707 seriesSpyArgs.clear();
708
709 QList<QVariant> setSpyArgs = setSpy1.takeFirst();
710 QCOMPARE(setSpyArgs.at(0).type(), QVariant::Bool);
711 QCOMPARE(setSpyArgs.at(0).toBool(), true);
712 setSpyArgs.clear();
713
714 // Move mouse from top of set 1 to top of set 2
715 QTest::mouseMove(widget: view.viewport(), pos: layout.value(akey: set2).center().toPoint());
716 QCoreApplication::processEvents(flags: QEventLoop::AllEvents, maxtime: 1000);
717
718 QCOMPARE(seriesSpy.count(), 2);
719 QCOMPARE(setSpy1.count(), 1);
720 QCOMPARE(setSpy2.count(), 1);
721
722 // Should leave set 1
723 seriesSpyArgs = seriesSpy.takeFirst();
724 QCOMPARE(qvariant_cast<QCandlestickSet *>(seriesSpyArgs.at(1)), set1);
725 QCOMPARE(seriesSpyArgs.at(0).type(), QVariant::Bool);
726 QCOMPARE(seriesSpyArgs.at(0).toBool(), false);
727 // Don't call seriesSpyArgs.clear() here
728
729 setSpyArgs = setSpy1.takeFirst();
730 QCOMPARE(setSpyArgs.at(0).type(), QVariant::Bool);
731 QCOMPARE(setSpyArgs.at(0).toBool(), false);
732 // Don't call setSpyArgs.clear() here
733
734 // Should enter set 2
735 seriesSpyArgs = seriesSpy.takeFirst();
736 QCOMPARE(qvariant_cast<QCandlestickSet *>(seriesSpyArgs.at(1)), set2);
737 QCOMPARE(seriesSpyArgs.at(0).type(), QVariant::Bool);
738 QCOMPARE(seriesSpyArgs.at(0).toBool(), true);
739 seriesSpyArgs.clear();
740
741 setSpyArgs = setSpy2.takeFirst();
742 QCOMPARE(setSpyArgs.at(0).type(), QVariant::Bool);
743 QCOMPARE(setSpyArgs.at(0).toBool(), true);
744 setSpyArgs.clear();
745
746 // Move mouse from top of set 2 to background
747 QTest::mouseMove(widget: view.viewport(), pos: QPoint(layout.value(akey: set2).center().x(), 0));
748 QCoreApplication::processEvents(flags: QEventLoop::AllEvents, maxtime: 1000);
749
750 QCOMPARE(seriesSpy.count(), 1);
751 QCOMPARE(setSpy1.count(), 0);
752 QCOMPARE(setSpy2.count(), 1);
753
754 // Should leave set 2
755 seriesSpyArgs = seriesSpy.takeFirst();
756 QCOMPARE(qvariant_cast<QCandlestickSet *>(seriesSpyArgs.at(1)), set2);
757 QCOMPARE(seriesSpyArgs.at(0).type(), QVariant::Bool);
758 QCOMPARE(seriesSpyArgs.at(0).toBool(), false);
759 seriesSpyArgs.clear();
760
761 setSpyArgs = setSpy2.takeFirst();
762 QCOMPARE(setSpyArgs.at(0).type(), QVariant::Bool);
763 QCOMPARE(setSpyArgs.at(0).toBool(), false);
764 setSpyArgs.clear();
765}
766
767void tst_QCandlestickSeries::mousePressed()
768{
769 SKIP_IF_CANNOT_TEST_MOUSE_EVENTS();
770
771 QVERIFY(m_series->append(m_sets));
772 QCOMPARE(m_series->count(), m_sets.count());
773
774 QCandlestickSet *set1 = m_series->sets().at(i: 1);
775 QCandlestickSet *set2 = m_series->sets().at(i: 2);
776
777 QSignalSpy seriesSpy(m_series, SIGNAL(pressed(QCandlestickSet *)));
778 QSignalSpy setSpy1(set1, SIGNAL(pressed()));
779 QSignalSpy setSpy2(set2, SIGNAL(pressed()));
780
781 QChartView view(new QChart());
782 view.resize(w: 400, h: 300);
783 view.chart()->addSeries(series: m_series);
784 view.chart()->createDefaultAxes();
785 view.show();
786 QVERIFY(QTest::qWaitForWindowExposed(&view));
787
788 // Calculate expected layout for candlesticks
789 QRectF plotArea = view.chart()->plotArea();
790 qreal candlestickWidth = plotArea.width() / m_series->count();
791 qreal candlestickHeight = plotArea.height();
792
793 QMap<QCandlestickSet *, QRectF> layout;
794 layout.insert(akey: set1, avalue: QRectF(plotArea.left() + candlestickWidth * m_sets.indexOf(t: set1),
795 plotArea.top(), candlestickWidth, candlestickHeight));
796 layout.insert(akey: set2, avalue: QRectF(plotArea.left() + candlestickWidth * m_sets.indexOf(t: set2),
797 plotArea.top(), candlestickWidth, candlestickHeight));
798
799 // Press set 1
800 QTest::mouseClick(widget: view.viewport(), button: Qt::LeftButton, stateKey: {}, pos: layout.value(akey: set1).center().toPoint());
801 QCoreApplication::processEvents(flags: QEventLoop::AllEvents, maxtime: 1000);
802
803 QCOMPARE(seriesSpy.count(), 1);
804 QCOMPARE(setSpy1.count(), 1);
805 QCOMPARE(setSpy2.count(), 0);
806
807 QList<QVariant> seriesSpyArgs = seriesSpy.takeFirst();
808 QCOMPARE(seriesSpyArgs.count(), 1);
809 QCOMPARE(qvariant_cast<QCandlestickSet *>(seriesSpyArgs.at(0)), set1);
810 seriesSpyArgs.clear();
811
812 QVERIFY(setSpy1.takeFirst().isEmpty());
813
814 // Press set 2
815 QTest::mouseClick(widget: view.viewport(), button: Qt::LeftButton, stateKey: {}, pos: layout.value(akey: set2).center().toPoint());
816 QCoreApplication::processEvents(flags: QEventLoop::AllEvents, maxtime: 1000);
817
818 QCOMPARE(seriesSpy.count(), 1);
819 QCOMPARE(setSpy1.count(), 0);
820 QCOMPARE(setSpy2.count(), 1);
821
822 seriesSpyArgs = seriesSpy.takeFirst();
823 QCOMPARE(seriesSpyArgs.count(), 1);
824 QCOMPARE(qvariant_cast<QCandlestickSet *>(seriesSpyArgs.at(0)), set2);
825 seriesSpyArgs.clear();
826
827 QVERIFY(setSpy2.takeFirst().isEmpty());
828}
829
830void tst_QCandlestickSeries::mouseReleased()
831{
832 SKIP_IF_CANNOT_TEST_MOUSE_EVENTS();
833
834 QVERIFY(m_series->append(m_sets));
835 QCOMPARE(m_series->count(), m_sets.count());
836
837 QCandlestickSet *set1 = m_series->sets().at(i: 1);
838 QCandlestickSet *set2 = m_series->sets().at(i: 2);
839
840 QSignalSpy seriesSpy(m_series, SIGNAL(released(QCandlestickSet *)));
841 QSignalSpy setSpy1(set1, SIGNAL(released()));
842 QSignalSpy setSpy2(set2, SIGNAL(released()));
843
844 QChartView view(new QChart());
845 view.resize(w: 400, h: 300);
846 view.chart()->addSeries(series: m_series);
847 view.chart()->createDefaultAxes();
848 view.show();
849 QVERIFY(QTest::qWaitForWindowExposed(&view));
850
851 // Calculate expected layout for candlesticks
852 QRectF plotArea = view.chart()->plotArea();
853 qreal candlestickWidth = plotArea.width() / m_series->count();
854 qreal candlestickHeight = plotArea.height();
855
856 QMap<QCandlestickSet *, QRectF> layout;
857 layout.insert(akey: set1, avalue: QRectF(plotArea.left() + candlestickWidth * m_sets.indexOf(t: set1),
858 plotArea.top(), candlestickWidth, candlestickHeight));
859 layout.insert(akey: set2, avalue: QRectF(plotArea.left() + candlestickWidth * m_sets.indexOf(t: set2),
860 plotArea.top(), candlestickWidth, candlestickHeight));
861
862 // Release mouse over set 1
863 QTest::mouseClick(widget: view.viewport(), button: Qt::LeftButton, stateKey: {}, pos: layout.value(akey: set1).center().toPoint());
864 QCoreApplication::processEvents(flags: QEventLoop::AllEvents, maxtime: 1000);
865
866 QCOMPARE(seriesSpy.count(), 1);
867 QCOMPARE(setSpy1.count(), 1);
868 QCOMPARE(setSpy2.count(), 0);
869
870 QList<QVariant> seriesSpyArgs = seriesSpy.takeFirst();
871 QCOMPARE(seriesSpyArgs.count(), 1);
872 QCOMPARE(qvariant_cast<QCandlestickSet *>(seriesSpyArgs.at(0)), set1);
873 seriesSpyArgs.clear();
874
875 QVERIFY(setSpy1.takeFirst().isEmpty());
876
877 // Release mouse over set 2
878 QTest::mouseClick(widget: view.viewport(), button: Qt::LeftButton, stateKey: {}, pos: layout.value(akey: set2).center().toPoint());
879 QCoreApplication::processEvents(flags: QEventLoop::AllEvents, maxtime: 1000);
880
881 QCOMPARE(seriesSpy.count(), 1);
882 QCOMPARE(setSpy1.count(), 0);
883 QCOMPARE(setSpy2.count(), 1);
884
885 seriesSpyArgs = seriesSpy.takeFirst();
886 QCOMPARE(seriesSpyArgs.count(), 1);
887 QCOMPARE(qvariant_cast<QCandlestickSet *>(seriesSpyArgs.at(0)), set2);
888 seriesSpyArgs.clear();
889
890 QVERIFY(setSpy2.takeFirst().isEmpty());
891}
892
893void tst_QCandlestickSeries::mouseDoubleClicked()
894{
895 SKIP_IF_CANNOT_TEST_MOUSE_EVENTS();
896
897 QVERIFY(m_series->append(m_sets));
898 QCOMPARE(m_series->count(), m_sets.count());
899
900 QCandlestickSet *set1 = m_series->sets().at(i: 1);
901 QCandlestickSet *set2 = m_series->sets().at(i: 2);
902
903 QSignalSpy seriesSpy(m_series, SIGNAL(doubleClicked(QCandlestickSet *)));
904 QSignalSpy setSpy1(set1, SIGNAL(doubleClicked()));
905 QSignalSpy setSpy2(set2, SIGNAL(doubleClicked()));
906
907 QChartView view(new QChart());
908 view.resize(w: 400, h: 300);
909 view.chart()->addSeries(series: m_series);
910 view.chart()->createDefaultAxes();
911 view.show();
912 QVERIFY(QTest::qWaitForWindowExposed(&view));
913
914 // Calculate expected layout for candlesticks
915 QRectF plotArea = view.chart()->plotArea();
916 qreal candlestickWidth = plotArea.width() / m_series->count();
917 qreal candlestickHeight = plotArea.height();
918
919 QMap<QCandlestickSet *, QRectF> layout;
920 layout.insert(akey: set1, avalue: QRectF(plotArea.left() + candlestickWidth * m_sets.indexOf(t: set1),
921 plotArea.top(), candlestickWidth, candlestickHeight));
922 layout.insert(akey: set2, avalue: QRectF(plotArea.left() + candlestickWidth * m_sets.indexOf(t: set2),
923 plotArea.top(), candlestickWidth, candlestickHeight));
924
925 // Double-click set 1
926 QTest::mouseDClick(widget: view.viewport(), button: Qt::LeftButton, stateKey: {}, pos: layout.value(akey: set1).center().toPoint());
927 QCoreApplication::processEvents(flags: QEventLoop::AllEvents, maxtime: 1000);
928
929 QCOMPARE(seriesSpy.count(), 1);
930 QCOMPARE(setSpy1.count(), 1);
931 QCOMPARE(setSpy2.count(), 0);
932
933 QList<QVariant> seriesSpyArgs = seriesSpy.takeFirst();
934 QCOMPARE(seriesSpyArgs.count(), 1);
935 QCOMPARE(qvariant_cast<QCandlestickSet *>(seriesSpyArgs.at(0)), set1);
936 seriesSpyArgs.clear();
937
938 QVERIFY(setSpy1.takeFirst().isEmpty());
939}
940
941QTEST_MAIN(tst_QCandlestickSeries)
942
943#include "tst_qcandlestickseries.moc"
944

source code of qtcharts/tests/auto/qcandlestickseries/tst_qcandlestickseries.cpp