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

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