1// Copyright (C) 2016 The Qt Company Ltd.
2// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only
3
4#include <QtCharts/QBarCategoryAxis>
5#include <QtCharts/QCandlestickLegendMarker>
6#include <QtCharts/QCandlestickSeries>
7#include <QtCharts/QCandlestickSet>
8#include <QtCharts/QValueAxis>
9#include <QtCore/QDateTime>
10#include <private/candlestickanimation_p.h>
11#include <private/candlestickchartitem_p.h>
12#include <private/chartdataset_p.h>
13#include <private/charttheme_p.h>
14#include <private/qcandlestickseries_p.h>
15#include <private/qcandlestickset_p.h>
16#include <private/qchart_p.h>
17
18QT_BEGIN_NAMESPACE
19
20/*!
21 \class QCandlestickSeries
22 \since 5.8
23 \inmodule QtCharts
24 \brief The QCandlestickSeries class presents data as candlesticks.
25
26 This class acts as a container for single candlestick items. Each item is drawn to its own category
27 when using QBarCategoryAxis. QDateTimeAxis and QValueAxis can be used as alternatives to
28 QBarCategoryAxis. In this case, each candlestick item is drawn according to its timestamp value.
29
30 \note The timestamps must be unique within a QCandlestickSeries. When using QBarCategoryAxis,
31 only the first one of the candlestick items sharing a timestamp is drawn. If the chart includes
32 multiple instances of QCandlestickSeries, items from different series sharing a timestamp are
33 drawn to the same category. When using QValueAxis or QDateTimeAxis, candlestick items sharing a
34 timestamp will overlap each other.
35
36 See the \l {Charts with Widgets Gallery} to learn how to create
37 a candlestick chart.
38 \image examples_candlestickchart.png
39
40 \sa QCandlestickSet, QBarCategoryAxis, QDateTimeAxis, QValueAxis
41*/
42
43/*!
44 \qmltype CandlestickSeries
45 \since QtCharts 2.2
46 \instantiates QCandlestickSeries
47 \inqmlmodule QtCharts
48 \inherits AbstractSeries
49 \brief Represents a series of data as candlesticks.
50
51 The CandlestickSeries type acts as a container for single candlestick items.
52 Each item is drawn to its own category
53 when using BarCategoryAxis. DateTimeAxis and ValueAxis can be used as an alternative to
54 BarCategoryAxis. In this case, each candlestick item is drawn according to its timestamp value.
55
56 \note The timestamps must be unique within a CandlestickSeries. When using BarCategoryAxis, only
57 the first one of the candlestick items sharing a timestamp is drawn. If the chart includes
58 multiple instances of CandlestickSeries, items from different series sharing a timestamp are
59 drawn to the same category. When using ValueAxis or DateTimeAxis, candlestick items sharing a
60 timestamp will overlap each other.
61
62 The following QML shows how to create a simple candlestick chart:
63 \code
64 import QtQuick 2.5
65 import QtCharts 2.2
66
67 ChartView {
68 title: "Candlestick Series"
69 width: 400
70 height: 300
71
72 CandlestickSeries {
73 name: "Acme Ltd."
74 increasingColor: "green"
75 decreasingColor: "red"
76
77 CandlestickSet { timestamp: 1435708800000; open: 690; high: 694; low: 599; close: 660 }
78 CandlestickSet { timestamp: 1435795200000; open: 669; high: 669; low: 669; close: 669 }
79 CandlestickSet { timestamp: 1436140800000; open: 485; high: 623; low: 485; close: 600 }
80 CandlestickSet { timestamp: 1436227200000; open: 589; high: 615; low: 377; close: 569 }
81 CandlestickSet { timestamp: 1436313600000; open: 464; high: 464; low: 254; close: 254 }
82 }
83 }
84 \endcode
85
86 \beginfloatleft
87 \image examples_qmlcandlestick.png
88 \endfloat
89 \clearfloat
90
91 \sa CandlestickSet, BarCategoryAxis, DateTimeAxis, ValueAxis
92*/
93
94/*!
95 \qmlproperty AbstractAxis CandlestickSeries::axisX
96 The x-axis used for the series. If you leave both axisX and axisXTop
97 undefined, a value axis is created for the series.
98 \sa axisXTop, ValueAxis
99*/
100
101/*!
102 \qmlproperty AbstractAxis CandlestickSeries::axisY
103 The y-axis used for the series. If you leave both axisY and axisYRight
104 undefined, a value axis is created for the series.
105 \sa axisYRight, ValueAxis
106*/
107
108/*!
109 \qmlproperty AbstractAxis CandlestickSeries::axisXTop
110 The x-axis used for the series, drawn on top of the chart view.
111
112 \note You can only provide either axisX or axisXTop, not both.
113 \sa axisX
114*/
115
116/*!
117 \qmlproperty AbstractAxis CandlestickSeries::axisYRight
118 The y-axis used for the series, drawn to the right on the chart view.
119
120 \note You can only provide either axisY or axisYRight, not both.
121 \sa axisY
122*/
123
124/*!
125 \property QCandlestickSeries::count
126 \brief The number of candlestick items in a series.
127*/
128
129/*!
130 \qmlproperty int CandlestickSeries::count
131 The number of candlestick items in a series.
132*/
133
134/*!
135 \property QCandlestickSeries::maximumColumnWidth
136 \brief The maximum width of the candlestick items in pixels. Setting a negative value means
137 there is no maximum width. All negative values are converted to -1.0.
138*/
139
140/*!
141 \qmlproperty real CandlestickSeries::maximumColumnWidth
142 The maximum width of the candlestick items in pixels. Setting a negative value means
143 there is no maximum width. All negative values are converted to -1.0.
144*/
145
146/*!
147 \property QCandlestickSeries::minimumColumnWidth
148 \brief The minimum width of the candlestick items in pixels. Setting a negative value means
149 there is no minimum width. All negative values are converted to -1.0.
150*/
151
152/*!
153 \qmlproperty real CandlestickSeries::minimumColumnWidth
154 The minimum width of the candlestick items in pixels. Setting a negative value means
155 there is no minimum width. All negative values are converted to -1.0.
156*/
157
158/*!
159 \property QCandlestickSeries::bodyWidth
160 \brief The relative width of the candlestick item within its own slot, in the range
161 from 0.0 to 1.0.
162
163 Values outside this range are clamped to 0.0 or 1.0.
164*/
165
166/*!
167 \qmlproperty real CandlestickSeries::bodyWidth
168 The relative width of the candlestick item within its own slot, in the range
169 from 0.0 to 1.0. Values outside this range are clamped to 0.0 or 1.0.
170*/
171
172/*!
173 \property QCandlestickSeries::bodyOutlineVisible
174 \brief The visibility of the candlestick body outline.
175*/
176
177/*!
178 \qmlproperty bool CandlestickSeries::bodyOutlineVisible
179 The visibility of the candlestick body outlines.
180*/
181
182/*!
183 \property QCandlestickSeries::capsWidth
184 \brief The relative width of the caps within a candlestick, in the range from 0.0
185 to 1.0.
186
187 Values outside this range are clamped to 0.0 or 1.0.
188*/
189
190/*!
191 \qmlproperty real CandlestickSeries::capsWidth
192 The relative width of the caps within a candlestick, in the range from 0.0
193 to 1.0. Values outside this range are clamped to 0.0 or 1.0.
194*/
195
196/*!
197 \property QCandlestickSeries::capsVisible
198 \brief The visibility of the caps.
199*/
200
201/*!
202 \qmlproperty bool CandlestickSeries::capsVisible
203 The visibility of the caps.
204*/
205
206/*!
207 \property QCandlestickSeries::increasingColor
208 \brief The color of the increasing candlestick item body.
209
210 A candlestick is \e increasing when its close value is higher than the open
211 value. By default, this property is set to the brush color. The default
212 color is used also when the property is set to an invalid color value.
213*/
214
215/*!
216 \qmlproperty color CandlestickSeries::increasingColor
217 The color of the increasing candlestick item body.
218 A candlestick is \e increasing when its close value is higher than the open
219 value. By default, this property is set to the brush color. The default
220 color is used also when the property is set to an invalid color value.
221*/
222
223/*!
224 \property QCandlestickSeries::decreasingColor
225 \brief The color of the decreasing candlestick item body.
226
227 A candlestick is \e decreasing when its open value is higher than the close
228 value. By default, this property is set to the brush color with the alpha
229 channel set to 128. The default color is used also when the property is set
230 to an invalid color value.
231*/
232
233/*!
234 \qmlproperty color CandlestickSeries::decreasingColor
235 The color of the decreasing candlestick item body.
236 A candlestick is \e decreasing when its open value is higher than the close
237 value. By default, this property is set to the brush color with the alpha
238 channel set to 128. The default color is used also when the property is set
239 to an invalid color value.
240*/
241
242/*!
243 \property QCandlestickSeries::brush
244 \brief The brush used to fill the candlestick items.
245*/
246
247/*!
248 \property QCandlestickSeries::pen
249 \brief The pen used to draw the lines of the candlestick items.
250*/
251
252/*!
253 \qmlproperty string CandlestickSeries::brushFilename
254 The name of the file used as a brush image for the series.
255*/
256
257/*!
258 \fn void QCandlestickSeries::clicked(QCandlestickSet *set)
259 This signal is emitted when the candlestick item specified by \a set
260 is clicked on the chart.
261*/
262
263/*!
264 \qmlsignal CandlestickSeries::clicked(CandlestickSet set)
265 This signal is emitted when the candlestick item specified by \a set
266 is clicked on the chart.
267
268 The corresponding signal handler is \c {onClicked}.
269*/
270
271/*!
272 \fn void QCandlestickSeries::hovered(bool status, QCandlestickSet *set)
273 This signal is emitted when a mouse is hovered over the candlestick
274 item specified by \a set in a chart.
275
276 When the mouse moves over the item, \a status turns \c true, and when the
277 mouse moves away again, it turns \c false.
278*/
279
280/*!
281 \qmlsignal CandlestickSeries::hovered(bool status, CandlestickSet set)
282 This signal is emitted when a mouse is hovered over the candlestick
283 item specified by \a set in a chart.
284
285 When the mouse moves over the item, \a status turns \c true, and when the
286 mouse moves away again, it turns \c false.
287
288 The corresponding signal handler is \c {onHovered}.
289*/
290
291/*!
292 \fn void QCandlestickSeries::pressed(QCandlestickSet *set)
293 This signal is emitted when the user clicks the candlestick item
294 specified by \a set and holds down the mouse button.
295*/
296
297/*!
298 \qmlsignal CandlestickSeries::pressed(CandlestickSet set)
299 This signal is emitted when the user clicks the candlestick item
300 specified by \a set and holds down the mouse button.
301
302 The corresponding signal handler is \c {onPressed}.
303*/
304
305/*!
306 \fn void QCandlestickSeries::released(QCandlestickSet *set)
307 This signal is emitted when the user releases the mouse press on the
308 candlestick item specified by \a set.
309*/
310
311/*!
312 \qmlsignal CandlestickSeries::released(CandlestickSet set)
313 This signal is emitted when the user releases the mouse press on the
314 candlestick item specified by \a set.
315
316 The corresponding signal handler is \c {onReleased}.
317*/
318
319/*!
320 \fn void QCandlestickSeries::doubleClicked(QCandlestickSet *set)
321 This signal is emitted when the candlestick item specified by \a set
322 is double-clicked on the chart.
323*/
324
325/*!
326 \qmlsignal CandlestickSeries::doubleClicked(CandlestickSet set)
327 This signal is emitted when the candlestick item specified by \a set
328 is double-clicked on the chart.
329
330 The corresponding signal handler is \c {onDoubleClicked}.
331*/
332
333/*!
334 \fn void QCandlestickSeries::candlestickSetsAdded(const QList<QCandlestickSet *> &sets)
335 This signal is emitted when the candlestick items specified by \a
336 sets are added to the series.
337*/
338
339/*!
340 \qmlsignal CandlestickSeries::candlestickSetsAdded(list<CandlestickSet> sets)
341 This signal is emitted when the candlestick items specified by
342 \a sets are added to the series.
343
344 The corresponding signal handler is \c {onCandlestickSetsAdded}.
345*/
346
347/*!
348 \fn void QCandlestickSeries::candlestickSetsRemoved(const QList<QCandlestickSet *> &sets)
349 This signal is emitted when the candlestick items specified by
350 \a sets are removed from the series.
351*/
352
353/*!
354 \qmlsignal CandlestickSeries::candlestickSetsRemoved(list<CandlestickSet> sets)
355 This signal is emitted when the candlestick items specified by
356 \a sets are removed from the series.
357
358 The corresponding signal handler is \c {onCandlestickSetsRemoved}.
359*/
360
361/*!
362 \fn void QCandlestickSeries::countChanged()
363 This signal is emitted when the number of candlestick items in the
364 series changes.
365 \sa count
366*/
367
368/*!
369 \fn void QCandlestickSeries::maximumColumnWidthChanged()
370 This signal is emitted when there is a change in the maximum column width of candlestick items.
371 \sa maximumColumnWidth
372*/
373
374/*!
375 \fn void QCandlestickSeries::minimumColumnWidthChanged()
376 This signal is emitted when there is a change in the minimum column width of candlestick items.
377 \sa minimumColumnWidth
378*/
379
380/*!
381 \fn void QCandlestickSeries::bodyWidthChanged()
382 This signal is emitted when the candlestick item width changes.
383 \sa bodyWidth
384*/
385
386/*!
387 \fn void QCandlestickSeries::bodyOutlineVisibilityChanged()
388 This signal is emitted when the visibility of the candlestick item body outline changes.
389 \sa bodyOutlineVisible
390*/
391
392/*!
393 \fn void QCandlestickSeries::capsWidthChanged()
394 This signal is emitted when the candlestick item caps width changes.
395 \sa capsWidth
396*/
397
398/*!
399 \fn void QCandlestickSeries::capsVisibilityChanged()
400 This signal is emitted when the visibility of the candlestick item caps changes.
401 \sa capsVisible
402*/
403
404/*!
405 \fn void QCandlestickSeries::increasingColorChanged()
406 This signal is emitted when the candlestick item increasing color changes.
407 \sa increasingColor
408*/
409
410/*!
411 \fn void QCandlestickSeries::decreasingColorChanged()
412 This signal is emitted when the candlestick item decreasing color changes.
413 \sa decreasingColor
414*/
415
416/*!
417 \fn void QCandlestickSeries::brushChanged()
418 This signal is emitted when the candlestick item brush changes.
419
420 \sa brush
421*/
422
423/*!
424 \fn void QCandlestickSeries::penChanged()
425 This signal is emitted when the candlestick item pen changes.
426
427 \sa pen
428*/
429
430/*!
431 \qmlmethod CandlestickSeries::at(int index)
432 Returns the candlestick item at the position specified by \a index. Returns
433 null if the index is not valid.
434*/
435
436/*!
437 Constructs an empty QCandlestickSeries. The \a parent is optional.
438*/
439QCandlestickSeries::QCandlestickSeries(QObject *parent)
440 : QAbstractSeries(*new QCandlestickSeriesPrivate(this), parent)
441{
442}
443
444/*!
445 Destroys the series. Removes the series from the chart.
446*/
447QCandlestickSeries::~QCandlestickSeries()
448{
449 Q_D(QCandlestickSeries);
450 if (d->m_chart)
451 d->m_chart->removeSeries(series: this);
452}
453
454/*!
455 \qmlmethod CandlestickSeries::append(CandlestickSet set)
456 Adds a single candlestick item specified by \a set to the series and takes
457 ownership of it. If the item is null or it is already in the series, it
458 is not appended.
459
460 Returns \c true if appending succeeded, \c false otherwise.
461*/
462
463/*!
464 Adds a single candlestick item specified by \a set to the series and takes
465 ownership of it. If the item is null or it is already in the series, it
466 is not appended.
467 Returns \c true if appending succeeded, \c false otherwise.
468*/
469bool QCandlestickSeries::append(QCandlestickSet *set)
470{
471 QList<QCandlestickSet *> sets;
472 sets.append(t: set);
473
474 return append(sets);
475}
476
477/*!
478 \qmlmethod CandlestickSeries::remove(CandlestickSet set)
479 Removes a single candlestick item, specified by \a set, from the series.
480
481 Returns \c true if the item is successfully deleted, \c false otherwise.
482*/
483
484/*!
485 Removes a single candlestick item, specified by \a set, from the series.
486 Returns \c true if the item is successfully deleted, \c false otherwise.
487*/
488bool QCandlestickSeries::remove(QCandlestickSet *set)
489{
490 QList<QCandlestickSet *> sets;
491 sets.append(t: set);
492
493 return remove(sets);
494}
495
496/*!
497 Adds a list of candlestick items specified by \a sets to the series and
498 takes ownership of it. If any of the items are null, already belong to
499 the series, or appear in the list more than once, nothing is appended.
500 Returns \c true if all items were appended successfully, \c false otherwise.
501*/
502bool QCandlestickSeries::append(const QList<QCandlestickSet *> &sets)
503{
504 Q_D(QCandlestickSeries);
505
506 bool success = d->append(sets);
507 if (success) {
508 emit candlestickSetsAdded(sets);
509 emit countChanged();
510 }
511
512 return success;
513}
514
515/*!
516 Removes a list of candlestick items specified by \a sets from the series. If
517 any of the items are null, were already removed from the series, or appear
518 in the list more than once, nothing is removed. Returns \c true if all items
519 were removed successfully, \c false otherwise.
520*/
521bool QCandlestickSeries::remove(const QList<QCandlestickSet *> &sets)
522{
523 Q_D(QCandlestickSeries);
524
525 bool success = d->remove(sets);
526 if (success) {
527 emit candlestickSetsRemoved(sets);
528 emit countChanged();
529 foreach (QCandlestickSet *set, sets)
530 delete set;
531 }
532
533 return success;
534}
535
536/*!
537 \qmlmethod CandlestickSeries::insert(int index, CandlestickSet set)
538 Inserts the candlestick item specified by \a set to the series at the
539 position specified by \a index. Takes ownership of the item. If the
540 item is null or already belongs to the series, it is not inserted.
541
542 Returns \c true if inserting succeeded, \c false otherwise.
543*/
544
545/*!
546 Inserts the candlestick item specified by \a set to the series at the
547 position specified by \a index. Takes ownership of the item. If the
548 item is null or already belongs to the series, it is not inserted.
549 Returns \c true if inserting succeeded, \c false otherwise.
550*/
551bool QCandlestickSeries::insert(int index, QCandlestickSet *set)
552{
553 Q_D(QCandlestickSeries);
554
555 bool success = d->insert(index, set);
556 if (success) {
557 QList<QCandlestickSet *> sets;
558 sets.append(t: set);
559 emit candlestickSetsAdded(sets);
560 emit countChanged();
561 }
562
563 return success;
564}
565
566/*!
567 Takes a single candlestick item, specified by \a set, from the series. Does
568 not delete the item. Returns \c true if the take operation was successful, \c false otherwise.
569 \note The series remains the item's parent object. You must set the parent
570 object to take full ownership.
571*/
572bool QCandlestickSeries::take(QCandlestickSet *set)
573{
574 Q_D(QCandlestickSeries);
575
576 QList<QCandlestickSet *> sets;
577 sets.append(t: set);
578
579 bool success = d->remove(sets);
580 if (success) {
581 emit candlestickSetsRemoved(sets);
582 emit countChanged();
583 }
584
585 return success;
586}
587
588/*!
589 \qmlmethod CandlestickSeries::clear()
590 Removes all candlestick items from the series and permanently deletes them.
591*/
592
593/*!
594 Removes all candlestick items from the series and permanently deletes them.
595*/
596void QCandlestickSeries::clear()
597{
598 Q_D(QCandlestickSeries);
599
600 QList<QCandlestickSet *> sets = this->sets();
601
602 bool success = d->remove(sets);
603 if (success) {
604 emit candlestickSetsRemoved(sets);
605 emit countChanged();
606 foreach (QCandlestickSet *set, sets)
607 delete set;
608 }
609}
610
611/*!
612 Returns the list of candlestick items in the series. Ownership of the
613 items does not change.
614 */
615QList<QCandlestickSet *> QCandlestickSeries::sets() const
616{
617 Q_D(const QCandlestickSeries);
618
619 return d->m_sets;
620}
621
622/*!
623 Returns the number of the candlestick items in the series.
624*/
625int QCandlestickSeries::count() const
626{
627 return sets().size();
628}
629
630/*!
631 Returns the type of the series (QAbstractSeries::SeriesTypeCandlestick).
632*/
633QAbstractSeries::SeriesType QCandlestickSeries::type() const
634{
635 return QAbstractSeries::SeriesTypeCandlestick;
636}
637
638void QCandlestickSeries::setMaximumColumnWidth(qreal maximumColumnWidth)
639{
640 Q_D(QCandlestickSeries);
641
642 if (maximumColumnWidth < 0.0 && maximumColumnWidth != -1.0)
643 maximumColumnWidth = -1.0;
644
645 if (d->m_maximumColumnWidth == maximumColumnWidth)
646 return;
647
648 d->m_maximumColumnWidth = maximumColumnWidth;
649
650 emit d->updatedLayout();
651 emit maximumColumnWidthChanged();
652}
653
654qreal QCandlestickSeries::maximumColumnWidth() const
655{
656 Q_D(const QCandlestickSeries);
657
658 return d->m_maximumColumnWidth;
659}
660
661void QCandlestickSeries::setMinimumColumnWidth(qreal minimumColumnWidth)
662{
663 Q_D(QCandlestickSeries);
664
665 if (minimumColumnWidth < 0.0 && minimumColumnWidth != -1.0)
666 minimumColumnWidth = -1.0;
667
668 if (d->m_minimumColumnWidth == minimumColumnWidth)
669 return;
670
671 d->m_minimumColumnWidth = minimumColumnWidth;
672
673 d->updatedLayout();
674 emit minimumColumnWidthChanged();
675}
676
677qreal QCandlestickSeries::minimumColumnWidth() const
678{
679 Q_D(const QCandlestickSeries);
680
681 return d->m_minimumColumnWidth;
682}
683
684void QCandlestickSeries::setBodyWidth(qreal bodyWidth)
685{
686 Q_D(QCandlestickSeries);
687
688 if (bodyWidth < 0.0)
689 bodyWidth = 0.0;
690 else if (bodyWidth > 1.0)
691 bodyWidth = 1.0;
692
693 if (d->m_bodyWidth == bodyWidth)
694 return;
695
696 d->m_bodyWidth = bodyWidth;
697
698 emit d->updatedLayout();
699 emit bodyWidthChanged();
700}
701
702qreal QCandlestickSeries::bodyWidth() const
703{
704 Q_D(const QCandlestickSeries);
705
706 return d->m_bodyWidth;
707}
708
709void QCandlestickSeries::setBodyOutlineVisible(bool bodyOutlineVisible)
710{
711 Q_D(QCandlestickSeries);
712
713 if (d->m_bodyOutlineVisible == bodyOutlineVisible)
714 return;
715
716 d->m_bodyOutlineVisible = bodyOutlineVisible;
717
718 emit d->updated();
719 emit bodyOutlineVisibilityChanged();
720}
721
722bool QCandlestickSeries::bodyOutlineVisible() const
723{
724 Q_D(const QCandlestickSeries);
725
726 return d->m_bodyOutlineVisible;
727}
728
729void QCandlestickSeries::setCapsWidth(qreal capsWidth)
730{
731 Q_D(QCandlestickSeries);
732
733 if (capsWidth < 0.0)
734 capsWidth = 0.0;
735 else if (capsWidth > 1.0)
736 capsWidth = 1.0;
737
738 if (d->m_capsWidth == capsWidth)
739 return;
740
741 d->m_capsWidth = capsWidth;
742
743 emit d->updatedLayout();
744 emit capsWidthChanged();
745}
746
747qreal QCandlestickSeries::capsWidth() const
748{
749 Q_D(const QCandlestickSeries);
750
751 return d->m_capsWidth;
752}
753
754void QCandlestickSeries::setCapsVisible(bool capsVisible)
755{
756 Q_D(QCandlestickSeries);
757
758 if (d->m_capsVisible == capsVisible)
759 return;
760
761 d->m_capsVisible = capsVisible;
762
763 emit d->updated();
764 emit capsVisibilityChanged();
765}
766
767bool QCandlestickSeries::capsVisible() const
768{
769 Q_D(const QCandlestickSeries);
770
771 return d->m_capsVisible;
772}
773
774void QCandlestickSeries::setIncreasingColor(const QColor &increasingColor)
775{
776 Q_D(QCandlestickSeries);
777
778 QColor color;
779 if (increasingColor.isValid()) {
780 color = increasingColor;
781 d->m_customIncreasingColor = true;
782 } else {
783 color = d->m_brush.color();
784 color.setAlpha(128);
785 d->m_customIncreasingColor = false;
786 }
787
788 if (d->m_increasingColor == color)
789 return;
790
791 d->m_increasingColor = color;
792
793 emit d->updated();
794 emit increasingColorChanged();
795}
796
797QColor QCandlestickSeries::increasingColor() const
798{
799 Q_D(const QCandlestickSeries);
800
801 return d->m_increasingColor;
802}
803
804void QCandlestickSeries::setDecreasingColor(const QColor &decreasingColor)
805{
806 Q_D(QCandlestickSeries);
807
808 QColor color;
809 if (decreasingColor.isValid()) {
810 color = decreasingColor;
811 d->m_customDecreasingColor = true;
812 } else {
813 color = d->m_brush.color();
814 d->m_customDecreasingColor = false;
815 }
816
817 if (d->m_decreasingColor == color)
818 return;
819
820 d->m_decreasingColor = color;
821
822 emit d->updated();
823 emit decreasingColorChanged();
824}
825
826QColor QCandlestickSeries::decreasingColor() const
827{
828 Q_D(const QCandlestickSeries);
829
830 return d->m_decreasingColor;
831}
832
833void QCandlestickSeries::setBrush(const QBrush &brush)
834{
835 Q_D(QCandlestickSeries);
836
837 if (d->m_brush == brush)
838 return;
839
840 d->m_brush = brush;
841 if (!d->m_customIncreasingColor) {
842 QColor color = d->m_brush.color();
843 color.setAlpha(128);
844 if (d->m_increasingColor != color) {
845 d->m_increasingColor = color;
846 emit increasingColorChanged();
847 }
848 }
849 if (!d->m_customDecreasingColor && d->m_decreasingColor != d->m_brush.color()) {
850 d->m_decreasingColor = d->m_brush.color();
851 emit decreasingColorChanged();
852 }
853
854 emit d->updated();
855 emit brushChanged();
856}
857
858QBrush QCandlestickSeries::brush() const
859{
860 Q_D(const QCandlestickSeries);
861
862 return d->m_brush;
863}
864
865void QCandlestickSeries::setPen(const QPen &pen)
866{
867 Q_D(QCandlestickSeries);
868
869 if (d->m_pen == pen)
870 return;
871
872 d->m_pen = pen;
873
874 emit d->updated();
875 emit penChanged();
876}
877
878QPen QCandlestickSeries::pen() const
879{
880 Q_D(const QCandlestickSeries);
881
882 return d->m_pen;
883}
884
885////////////////////////////////////////////////////////////////////////////////////////////////////
886
887QCandlestickSeriesPrivate::QCandlestickSeriesPrivate(QCandlestickSeries *q)
888 : QAbstractSeriesPrivate(q),
889 m_maximumColumnWidth(-1.0),
890 m_minimumColumnWidth(5.0),
891 m_bodyWidth(0.5),
892 m_bodyOutlineVisible(true),
893 m_capsWidth(0.5),
894 m_capsVisible(false),
895 m_increasingColor(QColor(Qt::transparent)),
896 m_decreasingColor(QChartPrivate::defaultBrush().color()),
897 m_customIncreasingColor(false),
898 m_customDecreasingColor(false),
899 m_brush(QChartPrivate::defaultBrush()),
900 m_pen(QChartPrivate::defaultPen()),
901 m_animation(nullptr)
902{
903}
904
905QCandlestickSeriesPrivate::~QCandlestickSeriesPrivate()
906{
907 disconnect(sender: this, signal: 0, receiver: 0, member: 0);
908 qDeleteAll(c: m_sets);
909}
910
911void QCandlestickSeriesPrivate::initializeDomain()
912{
913 qreal minX(domain()->minX());
914 qreal maxX(domain()->maxX());
915 qreal minY(domain()->minY());
916 qreal maxY(domain()->maxY());
917
918 if (m_sets.size()) {
919 QCandlestickSet *set = m_sets.first();
920 minX = set->timestamp();
921 maxX = set->timestamp();
922 minY = set->low();
923 maxY = set->high();
924 for (int i = 1; i < m_sets.size(); ++i) {
925 set = m_sets.at(i);
926 minX = qMin(a: minX, b: qreal(set->timestamp()));
927 maxX = qMax(a: maxX, b: qreal(set->timestamp()));
928 minY = qMin(a: minY, b: set->low());
929 maxY = qMax(a: maxY, b: set->high());
930 }
931 qreal extra = (maxX - minX) / m_sets.size() / 2;
932 minX = minX - extra;
933 maxX = maxX + extra;
934 }
935
936 domain()->setRange(minX, maxX, minY, maxY);
937}
938
939void QCandlestickSeriesPrivate::initializeAxes()
940{
941 foreach (QAbstractAxis* axis, m_axes) {
942 if (axis->type() == QAbstractAxis::AxisTypeBarCategory) {
943 if (axis->orientation() == Qt::Horizontal)
944 populateBarCategories(axis: qobject_cast<QBarCategoryAxis *>(object: axis));
945 }
946 }
947}
948
949void QCandlestickSeriesPrivate::initializeTheme(int index, ChartTheme* theme, bool forced)
950{
951 Q_Q(QCandlestickSeries);
952
953 if (forced || QChartPrivate::defaultBrush() == m_brush) {
954 const QList<QGradient> gradients = theme->seriesGradients();
955 const QGradient gradient = gradients.at(i: index % gradients.size());
956 const QBrush brush(ChartThemeManager::colorAt(gradient, pos: 0.5));
957 q->setBrush(brush);
958 }
959
960 if (forced || QChartPrivate::defaultPen() == m_pen) {
961 QPen pen = theme->outlinePen();
962 pen.setCosmetic(true);
963 q->setPen(pen);
964 }
965}
966
967void QCandlestickSeriesPrivate::initializeGraphics(QGraphicsItem *parent)
968{
969 Q_Q(QCandlestickSeries);
970
971 CandlestickChartItem *item = new CandlestickChartItem(q, parent);
972 m_item.reset(p: item);
973 QAbstractSeriesPrivate::initializeGraphics(parent);
974
975 if (m_chart) {
976 connect(sender: m_chart->d_ptr->m_dataset, SIGNAL(seriesAdded(QAbstractSeries *)),
977 receiver: this, SLOT(handleSeriesChange(QAbstractSeries *)));
978 connect(sender: m_chart->d_ptr->m_dataset, SIGNAL(seriesRemoved(QAbstractSeries *)),
979 receiver: this, SLOT(handleSeriesRemove(QAbstractSeries *)));
980
981 item->handleCandlestickSeriesChange();
982 }
983}
984
985void QCandlestickSeriesPrivate::initializeAnimations(QChart::AnimationOptions options, int duration,
986 QEasingCurve &curve)
987{
988 CandlestickChartItem *item = static_cast<CandlestickChartItem *>(m_item.get());
989 Q_ASSERT(item);
990
991 if (item->animation())
992 item->animation()->stopAndDestroyLater();
993
994 if (options.testFlag(flag: QChart::SeriesAnimations))
995 m_animation = new CandlestickAnimation(item, duration, curve);
996 else
997 m_animation = nullptr;
998 item->setAnimation(m_animation);
999
1000 QAbstractSeriesPrivate::initializeAnimations(options, duration, curve);
1001}
1002
1003QList<QLegendMarker *> QCandlestickSeriesPrivate::createLegendMarkers(QLegend *legend)
1004{
1005 Q_Q(QCandlestickSeries);
1006
1007 QList<QLegendMarker *> list;
1008
1009 return list << new QCandlestickLegendMarker(q, legend);
1010}
1011
1012QAbstractAxis::AxisType QCandlestickSeriesPrivate::defaultAxisType(Qt::Orientation orientation) const
1013{
1014 if (orientation == Qt::Horizontal)
1015 return QAbstractAxis::AxisTypeBarCategory;
1016
1017 if (orientation == Qt::Vertical)
1018 return QAbstractAxis::AxisTypeValue;
1019
1020 return QAbstractAxis::AxisTypeNoAxis;
1021}
1022
1023QAbstractAxis* QCandlestickSeriesPrivate::createDefaultAxis(Qt::Orientation orientation) const
1024{
1025 const QAbstractAxis::AxisType axisType = defaultAxisType(orientation);
1026
1027 if (axisType == QAbstractAxis::AxisTypeBarCategory)
1028 return new QBarCategoryAxis;
1029
1030 if (axisType == QAbstractAxis::AxisTypeValue)
1031 return new QValueAxis;
1032
1033 return 0; // axisType == QAbstractAxis::AxisTypeNoAxis
1034}
1035
1036bool QCandlestickSeriesPrivate::append(const QList<QCandlestickSet *> &sets)
1037{
1038 foreach (QCandlestickSet *set, sets) {
1039 if ((set == 0) || m_sets.contains(t: set) || set->d_ptr->m_series)
1040 return false; // Fail if any of the sets is null or is already appended.
1041 if (sets.count(t: set) != 1)
1042 return false; // Also fail if the same set occurs more than once in the given list.
1043 }
1044
1045 foreach (QCandlestickSet *set, sets) {
1046 m_sets.append(t: set);
1047 connect(sender: set->d_func(), SIGNAL(updatedLayout()), receiver: this, SIGNAL(updatedLayout()));
1048 connect(sender: set->d_func(), SIGNAL(updatedCandlestick()), receiver: this, SIGNAL(updatedCandlesticks()));
1049 set->d_ptr->m_series = this;
1050 }
1051
1052 return true;
1053}
1054
1055bool QCandlestickSeriesPrivate::remove(const QList<QCandlestickSet *> &sets)
1056{
1057 if (sets.size() == 0)
1058 return false;
1059
1060 foreach (QCandlestickSet *set, sets) {
1061 if ((set == 0) || (!m_sets.contains(t: set)))
1062 return false; // Fail if any of the sets is null or is not in series.
1063 if (sets.count(t: set) != 1)
1064 return false; // Also fail if the same set occurs more than once in the given list.
1065 }
1066
1067 foreach (QCandlestickSet *set, sets) {
1068 set->d_ptr->m_series = nullptr;
1069 m_sets.removeOne(t: set);
1070 disconnect(sender: set->d_func(), SIGNAL(updatedLayout()), receiver: this, SIGNAL(updatedLayout()));
1071 disconnect(sender: set->d_func(), SIGNAL(updatedCandlestick()),receiver: this, SIGNAL(updatedCandlesticks()));
1072 }
1073
1074 return true;
1075}
1076
1077bool QCandlestickSeriesPrivate::insert(int index, QCandlestickSet *set)
1078{
1079 if ((m_sets.contains(t: set)) || (set == 0) || set->d_ptr->m_series)
1080 return false; // Fail if set is already in list or set is null.
1081
1082 m_sets.insert(i: index, t: set);
1083 connect(sender: set->d_func(), SIGNAL(updatedLayout()), receiver: this, SIGNAL(updatedLayout()));
1084 connect(sender: set->d_func(), SIGNAL(updatedCandlestick()), receiver: this, SIGNAL(updatedCandlesticks()));
1085 set->d_ptr->m_series = this;
1086
1087 return true;
1088}
1089
1090void QCandlestickSeriesPrivate::handleSeriesChange(QAbstractSeries *series)
1091{
1092 Q_UNUSED(series);
1093
1094 if (m_chart) {
1095 CandlestickChartItem *item = static_cast<CandlestickChartItem *>(m_item.get());
1096 if (item)
1097 item->handleCandlestickSeriesChange();
1098 }
1099}
1100
1101void QCandlestickSeriesPrivate::handleSeriesRemove(QAbstractSeries *series)
1102{
1103 Q_Q(const QCandlestickSeries);
1104
1105 QCandlestickSeries *removedSeries = static_cast<QCandlestickSeries *>(series);
1106
1107 if (q == removedSeries && m_animation) {
1108 m_animation->stopAll();
1109 disconnect(sender: m_chart->d_ptr->m_dataset, signal: 0, receiver: removedSeries->d_func(), member: 0);
1110 }
1111
1112 if (q != removedSeries) {
1113 CandlestickChartItem *item = static_cast<CandlestickChartItem *>(m_item.get());
1114 if (item)
1115 item->handleCandlestickSeriesChange();
1116 }
1117}
1118
1119void QCandlestickSeriesPrivate::populateBarCategories(QBarCategoryAxis *axis)
1120{
1121 if (axis->categories().isEmpty()) {
1122 QStringList categories;
1123 for (int i = 0; i < m_sets.size(); ++i) {
1124 const qint64 timestamp = qRound64(d: m_sets.at(i)->timestamp());
1125 const QString timestampFormat = m_chart->locale().dateTimeFormat(format: QLocale::ShortFormat);
1126 categories << QDateTime::fromMSecsSinceEpoch(msecs: timestamp).toString(format: timestampFormat);
1127 }
1128 axis->append(categories);
1129 }
1130}
1131
1132QT_END_NAMESPACE
1133
1134#include "moc_qcandlestickseries.cpp"
1135#include "moc_qcandlestickseries_p.cpp"
1136

source code of qtcharts/src/charts/candlestickchart/qcandlestickseries.cpp