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/QCandlestickModelMapper> |
31 | #include <QtCharts/QCandlestickSeries> |
32 | #include <QtCharts/QCandlestickSet> |
33 | #include <QtCore/QAbstractItemModel> |
34 | #include <private/qcandlestickmodelmapper_p.h> |
35 | |
36 | #include <algorithm> |
37 | |
38 | QT_CHARTS_BEGIN_NAMESPACE |
39 | |
40 | /*! |
41 | \class QCandlestickModelMapper |
42 | \since 5.8 |
43 | \inmodule QtCharts |
44 | \brief Abstract model mapper class for candlestick series. |
45 | |
46 | Model mappers allow the use of a QAbstractItemModel-derived model as a data source for a chart |
47 | series, creating a connection between a QCandlestickSeries and the model object. A model mapper |
48 | maintains an equal size across all \l {QCandlestickSet} {QCandlestickSets}. |
49 | |
50 | \note The model used must support adding and removing rows/columns and modifying the data of the |
51 | cells. |
52 | */ |
53 | |
54 | /*! |
55 | \property QCandlestickModelMapper::model |
56 | \brief Defines the model that is used by the mapper. |
57 | */ |
58 | |
59 | /*! |
60 | \property QCandlestickModelMapper::series |
61 | \brief Defines the QCandlestickSeries object that is used by the mapper. |
62 | |
63 | \note All data in the series is discarded when it is set to the mapper. When a new series is |
64 | specified, the old series is disconnected (preserving its data). |
65 | */ |
66 | |
67 | /*! |
68 | \fn Qt::Orientation QCandlestickModelMapper::orientation() const |
69 | Returns the orientation that is used when QCandlestickModelMapper accesses the model. This |
70 | determines whether the consecutive values of the set are read from rows (Qt::Horizontal) or from |
71 | columns (Qt::Vertical). |
72 | */ |
73 | |
74 | /*! |
75 | \fn void QCandlestickModelMapper::modelReplaced() |
76 | \brief Emitted when the model, to which the mapper is connected, has changed. |
77 | \sa model |
78 | */ |
79 | |
80 | /*! |
81 | \fn void QCandlestickModelMapper::seriesReplaced() |
82 | \brief Emitted when the series to which mapper is connected to has changed. |
83 | \sa series |
84 | */ |
85 | |
86 | /*! |
87 | Constructs a model mapper object as a child of \a parent. |
88 | */ |
89 | QCandlestickModelMapper::QCandlestickModelMapper(QObject *parent) |
90 | : QObject(parent), |
91 | d_ptr(new QCandlestickModelMapperPrivate(this)) |
92 | { |
93 | } |
94 | |
95 | void QCandlestickModelMapper::setModel(QAbstractItemModel *model) |
96 | { |
97 | Q_D(QCandlestickModelMapper); |
98 | |
99 | if (d->m_model == model) |
100 | return; |
101 | |
102 | if (d->m_model) |
103 | disconnect(sender: d->m_model, signal: 0, receiver: d, member: 0); |
104 | |
105 | d->m_model = model; |
106 | emit modelReplaced(); |
107 | |
108 | if (!d->m_model) |
109 | return; |
110 | |
111 | d->initializeCandlestickFromModel(); |
112 | // connect signals from the model |
113 | connect(sender: d->m_model, SIGNAL(modelReset()), receiver: d, SLOT(initializeCandlestickFromModel())); |
114 | connect(sender: d->m_model, SIGNAL(dataChanged(QModelIndex, QModelIndex)), |
115 | receiver: d, SLOT(modelDataUpdated(QModelIndex, QModelIndex))); |
116 | connect(sender: d->m_model, SIGNAL(headerDataChanged(Qt::Orientation, int, int)), |
117 | receiver: d, SLOT(modelHeaderDataUpdated(Qt::Orientation, int, int))); |
118 | connect(sender: d->m_model, SIGNAL(rowsInserted(QModelIndex, int, int)), |
119 | receiver: d, SLOT(modelRowsInserted(QModelIndex, int, int))); |
120 | connect(sender: d->m_model, SIGNAL(rowsRemoved(QModelIndex, int, int)), |
121 | receiver: d, SLOT(modelRowsRemoved(QModelIndex, int, int))); |
122 | connect(sender: d->m_model, SIGNAL(columnsInserted(QModelIndex, int, int)), |
123 | receiver: d, SLOT(modelColumnsInserted(QModelIndex, int, int))); |
124 | connect(sender: d->m_model, SIGNAL(columnsRemoved(QModelIndex, int, int)), |
125 | receiver: d, SLOT(modelColumnsRemoved(QModelIndex, int, int))); |
126 | connect(sender: d->m_model, SIGNAL(destroyed()), receiver: d, SLOT(modelDestroyed())); |
127 | } |
128 | |
129 | QAbstractItemModel *QCandlestickModelMapper::model() const |
130 | { |
131 | Q_D(const QCandlestickModelMapper); |
132 | |
133 | return d->m_model; |
134 | } |
135 | |
136 | void QCandlestickModelMapper::setSeries(QCandlestickSeries *series) |
137 | { |
138 | Q_D(QCandlestickModelMapper); |
139 | |
140 | if (d->m_series == series) |
141 | return; |
142 | |
143 | if (d->m_series) |
144 | disconnect(sender: d->m_series, signal: 0, receiver: d, member: 0); |
145 | |
146 | d->m_series = series; |
147 | emit seriesReplaced(); |
148 | |
149 | if (!d->m_series) |
150 | return; |
151 | |
152 | d->initializeCandlestickFromModel(); |
153 | // connect the signals from the series |
154 | connect(sender: d->m_series, SIGNAL(candlestickSetsAdded(QList<QCandlestickSet *>)), |
155 | receiver: d, SLOT(candlestickSetsAdded(QList<QCandlestickSet *>))); |
156 | connect(sender: d->m_series, SIGNAL(candlestickSetsRemoved(QList<QCandlestickSet*>)), |
157 | receiver: d, SLOT(candlestickSetsRemoved(QList<QCandlestickSet *>))); |
158 | connect(sender: d->m_series, SIGNAL(destroyed()), receiver: d, SLOT(seriesDestroyed())); |
159 | } |
160 | |
161 | QCandlestickSeries *QCandlestickModelMapper::series() const |
162 | { |
163 | Q_D(const QCandlestickModelMapper); |
164 | |
165 | return d->m_series; |
166 | } |
167 | |
168 | /*! |
169 | Sets the row/column of the model that contains the \a timestamp values of the sets in the |
170 | series. Default value is -1 (invalid mapping). |
171 | */ |
172 | void QCandlestickModelMapper::setTimestamp(int timestamp) |
173 | { |
174 | Q_D(QCandlestickModelMapper); |
175 | |
176 | timestamp = qMax(a: timestamp, b: -1); |
177 | |
178 | if (d->m_timestamp == timestamp) |
179 | return; |
180 | |
181 | d->m_timestamp = timestamp; |
182 | emit d->timestampChanged(); |
183 | d->initializeCandlestickFromModel(); |
184 | } |
185 | |
186 | /*! |
187 | Returns the row/column of the model that contains the timestamp values of the sets in the |
188 | series. Default value is -1 (invalid mapping). |
189 | */ |
190 | int QCandlestickModelMapper::timestamp() const |
191 | { |
192 | Q_D(const QCandlestickModelMapper); |
193 | |
194 | return d->m_timestamp; |
195 | } |
196 | |
197 | /*! |
198 | Sets the row/column of the model that contains the \a open values of the sets in the series. |
199 | Default value is -1 (invalid mapping). |
200 | */ |
201 | void QCandlestickModelMapper::setOpen(int open) |
202 | { |
203 | Q_D(QCandlestickModelMapper); |
204 | |
205 | open = qMax(a: open, b: -1); |
206 | |
207 | if (d->m_open == open) |
208 | return; |
209 | |
210 | d->m_open = open; |
211 | emit d->openChanged(); |
212 | d->initializeCandlestickFromModel(); |
213 | } |
214 | |
215 | /*! |
216 | Returns the row/column of the model that contains the open values of the sets in the series. |
217 | Default value is -1 (invalid mapping). |
218 | */ |
219 | int QCandlestickModelMapper::open() const |
220 | { |
221 | Q_D(const QCandlestickModelMapper); |
222 | |
223 | return d->m_open; |
224 | } |
225 | |
226 | /*! |
227 | Sets the row/column of the model that contains the \a high values of the sets in the series. |
228 | Default value is -1 (invalid mapping). |
229 | */ |
230 | void QCandlestickModelMapper::setHigh(int high) |
231 | { |
232 | Q_D(QCandlestickModelMapper); |
233 | |
234 | high = qMax(a: high, b: -1); |
235 | |
236 | if (d->m_high == high) |
237 | return; |
238 | |
239 | d->m_high = high; |
240 | emit d->highChanged(); |
241 | d->initializeCandlestickFromModel(); |
242 | } |
243 | |
244 | /*! |
245 | Returns the row/column of the model that contains the high values of the sets in the series. |
246 | Default value is -1 (invalid mapping). |
247 | */ |
248 | int QCandlestickModelMapper::high() const |
249 | { |
250 | Q_D(const QCandlestickModelMapper); |
251 | |
252 | return d->m_high; |
253 | } |
254 | |
255 | /*! |
256 | Sets the row/column of the model that contains the \a low values of the sets in the series. |
257 | Default value is -1 (invalid mapping). |
258 | */ |
259 | void QCandlestickModelMapper::setLow(int low) |
260 | { |
261 | Q_D(QCandlestickModelMapper); |
262 | |
263 | low = qMax(a: low, b: -1); |
264 | |
265 | if (d->m_low == low) |
266 | return; |
267 | |
268 | d->m_low = low; |
269 | emit d->lowChanged(); |
270 | d->initializeCandlestickFromModel(); |
271 | } |
272 | |
273 | /*! |
274 | Returns the row/column of the model that contains the low values of the sets in the series. |
275 | Default value is -1 (invalid mapping). |
276 | */ |
277 | int QCandlestickModelMapper::low() const |
278 | { |
279 | Q_D(const QCandlestickModelMapper); |
280 | |
281 | return d->m_low; |
282 | } |
283 | |
284 | /*! |
285 | Sets the row/column of the model that contains the \a close values of the sets in the series. |
286 | Default value is -1 (invalid mapping). |
287 | */ |
288 | void QCandlestickModelMapper::setClose(int close) |
289 | { |
290 | Q_D(QCandlestickModelMapper); |
291 | |
292 | close = qMax(a: close, b: -1); |
293 | |
294 | if (d->m_close == close) |
295 | return; |
296 | |
297 | d->m_close = close; |
298 | emit d->closeChanged(); |
299 | d->initializeCandlestickFromModel(); |
300 | } |
301 | |
302 | /*! |
303 | Returns the row/column of the model that contains the close values of the sets in the series. |
304 | Default value is -1 (invalid mapping). |
305 | */ |
306 | int QCandlestickModelMapper::close() const |
307 | { |
308 | Q_D(const QCandlestickModelMapper); |
309 | |
310 | return d->m_close; |
311 | } |
312 | |
313 | /*! |
314 | Sets the section of the model that is used as the data source for the first candlestick set. |
315 | Parameter \a firstSetSection specifies the section of the model. Default value is -1. |
316 | */ |
317 | void QCandlestickModelMapper::setFirstSetSection(int firstSetSection) |
318 | { |
319 | Q_D(QCandlestickModelMapper); |
320 | |
321 | firstSetSection = qMax(a: firstSetSection, b: -1); |
322 | |
323 | if (d->m_firstSetSection == firstSetSection) |
324 | return; |
325 | |
326 | d->m_firstSetSection = firstSetSection; |
327 | emit d->firstSetSectionChanged(); |
328 | d->initializeCandlestickFromModel(); |
329 | } |
330 | |
331 | /*! |
332 | Returns the section of the model that is used as the data source for the first candlestick set. |
333 | Default value is -1 (invalid mapping). |
334 | */ |
335 | int QCandlestickModelMapper::firstSetSection() const |
336 | { |
337 | Q_D(const QCandlestickModelMapper); |
338 | |
339 | return d->m_firstSetSection; |
340 | } |
341 | |
342 | /*! |
343 | Sets the section of the model that is used as the data source for the last candlestick set. |
344 | Parameter \a lastSetSection specifies the section of the model. Default value is -1. |
345 | */ |
346 | void QCandlestickModelMapper::setLastSetSection(int lastSetSection) |
347 | { |
348 | Q_D(QCandlestickModelMapper); |
349 | |
350 | lastSetSection = qMax(a: lastSetSection, b: -1); |
351 | |
352 | if (d->m_lastSetSection == lastSetSection) |
353 | return; |
354 | |
355 | d->m_lastSetSection = lastSetSection; |
356 | emit d->lastSetSectionChanged(); |
357 | d->initializeCandlestickFromModel(); |
358 | } |
359 | |
360 | /*! |
361 | Returns the section of the model that is used as the data source for the last candlestick set. |
362 | Default value is -1 (invalid mapping). |
363 | */ |
364 | int QCandlestickModelMapper::lastSetSection() const |
365 | { |
366 | Q_D(const QCandlestickModelMapper); |
367 | |
368 | return d->m_lastSetSection; |
369 | } |
370 | |
371 | //////////////////////////////////////////////////////////////////////////////////////////////////// |
372 | |
373 | QCandlestickModelMapperPrivate::QCandlestickModelMapperPrivate(QCandlestickModelMapper *q) |
374 | : QObject(q), |
375 | m_model(nullptr), |
376 | m_series(nullptr), |
377 | m_timestamp(-1), |
378 | m_open(-1), |
379 | m_high(-1), |
380 | m_low(-1), |
381 | m_close(-1), |
382 | m_firstSetSection(-1), |
383 | m_lastSetSection(-1), |
384 | m_modelSignalsBlock(false), |
385 | m_seriesSignalsBlock(false), |
386 | q_ptr(q) |
387 | { |
388 | } |
389 | |
390 | void QCandlestickModelMapperPrivate::initializeCandlestickFromModel() |
391 | { |
392 | if (!m_model || !m_series) |
393 | return; |
394 | |
395 | blockSeriesSignals(); |
396 | // clear current content |
397 | m_series->clear(); |
398 | m_sets.clear(); |
399 | |
400 | // create the initial candlestick sets |
401 | QList<QCandlestickSet *> sets; |
402 | for (int i = m_firstSetSection; i <= m_lastSetSection; ++i) { |
403 | QModelIndex timestampIndex = candlestickModelIndex(section: i, pos: m_timestamp); |
404 | QModelIndex openIndex = candlestickModelIndex(section: i, pos: m_open); |
405 | QModelIndex highIndex = candlestickModelIndex(section: i, pos: m_high); |
406 | QModelIndex lowIndex = candlestickModelIndex(section: i, pos: m_low); |
407 | QModelIndex closeIndex = candlestickModelIndex(section: i, pos: m_close); |
408 | if (timestampIndex.isValid() |
409 | && openIndex.isValid() |
410 | && highIndex.isValid() |
411 | && lowIndex.isValid() |
412 | && closeIndex.isValid()) { |
413 | QCandlestickSet *set = new QCandlestickSet(); |
414 | set->setTimestamp(m_model->data(index: timestampIndex, role: Qt::DisplayRole).toReal()); |
415 | set->setOpen(m_model->data(index: openIndex, role: Qt::DisplayRole).toReal()); |
416 | set->setHigh(m_model->data(index: highIndex, role: Qt::DisplayRole).toReal()); |
417 | set->setLow(m_model->data(index: lowIndex, role: Qt::DisplayRole).toReal()); |
418 | set->setClose(m_model->data(index: closeIndex, role: Qt::DisplayRole).toReal()); |
419 | |
420 | connect(sender: set, SIGNAL(timestampChanged()), receiver: this, SLOT(candlestickSetChanged())); |
421 | connect(sender: set, SIGNAL(openChanged()), receiver: this, SLOT(candlestickSetChanged())); |
422 | connect(sender: set, SIGNAL(highChanged()), receiver: this, SLOT(candlestickSetChanged())); |
423 | connect(sender: set, SIGNAL(lowChanged()), receiver: this, SLOT(candlestickSetChanged())); |
424 | connect(sender: set, SIGNAL(closeChanged()), receiver: this, SLOT(candlestickSetChanged())); |
425 | |
426 | sets.append(t: set); |
427 | } else { |
428 | break; |
429 | } |
430 | } |
431 | m_series->append(sets); |
432 | m_sets.append(t: sets); |
433 | blockSeriesSignals(block: false); |
434 | } |
435 | |
436 | void QCandlestickModelMapperPrivate::modelDataUpdated(QModelIndex topLeft, QModelIndex bottomRight) |
437 | { |
438 | Q_Q(QCandlestickModelMapper); |
439 | |
440 | if (!m_model || !m_series) |
441 | return; |
442 | |
443 | if (m_modelSignalsBlock) |
444 | return; |
445 | |
446 | blockSeriesSignals(); |
447 | QModelIndex index; |
448 | for (int row = topLeft.row(); row <= bottomRight.row(); ++row) { |
449 | for (int column = topLeft.column(); column <= bottomRight.column(); ++column) { |
450 | index = topLeft.sibling(arow: row, acolumn: column); |
451 | QCandlestickSet *set = candlestickSet(index); |
452 | if (set) { |
453 | int pos = (q->orientation() == Qt::Vertical) ? row : column; |
454 | if (pos == m_timestamp) |
455 | set->setTimestamp(m_model->data(index).toReal()); |
456 | else if (pos == m_open) |
457 | set->setOpen(m_model->data(index).toReal()); |
458 | else if (pos == m_high) |
459 | set->setHigh(m_model->data(index).toReal()); |
460 | else if (pos == m_low) |
461 | set->setLow(m_model->data(index).toReal()); |
462 | else if (pos == m_close) |
463 | set->setClose(m_model->data(index).toReal()); |
464 | } |
465 | } |
466 | } |
467 | blockSeriesSignals(block: false); |
468 | } |
469 | |
470 | void QCandlestickModelMapperPrivate::modelHeaderDataUpdated(Qt::Orientation orientation, int first, |
471 | int last) |
472 | { |
473 | Q_UNUSED(orientation); |
474 | Q_UNUSED(first); |
475 | Q_UNUSED(last); |
476 | } |
477 | |
478 | void QCandlestickModelMapperPrivate::modelRowsInserted(QModelIndex parent, int start, int end) |
479 | { |
480 | Q_UNUSED(parent) |
481 | |
482 | Q_Q(QCandlestickModelMapper); |
483 | |
484 | if (m_modelSignalsBlock) |
485 | return; |
486 | |
487 | blockSeriesSignals(); |
488 | if (q->orientation() == Qt::Vertical) |
489 | insertData(start, end); |
490 | else if (start <= m_firstSetSection || start <= m_lastSetSection) |
491 | initializeCandlestickFromModel(); // if the changes affect the map - reinitialize |
492 | blockSeriesSignals(block: false); |
493 | } |
494 | |
495 | void QCandlestickModelMapperPrivate::modelRowsRemoved(QModelIndex parent, int start, int end) |
496 | { |
497 | Q_UNUSED(parent) |
498 | |
499 | Q_Q(QCandlestickModelMapper); |
500 | |
501 | if (m_modelSignalsBlock) |
502 | return; |
503 | |
504 | blockSeriesSignals(); |
505 | if (q->orientation() == Qt::Vertical) |
506 | removeData(start, end); |
507 | else if (start <= m_firstSetSection || start <= m_lastSetSection) |
508 | initializeCandlestickFromModel(); // if the changes affect the map - reinitialize |
509 | blockSeriesSignals(block: false); |
510 | } |
511 | |
512 | void QCandlestickModelMapperPrivate::modelColumnsInserted(QModelIndex parent, int start, int end) |
513 | { |
514 | Q_UNUSED(parent) |
515 | |
516 | Q_Q(QCandlestickModelMapper); |
517 | |
518 | if (m_modelSignalsBlock) |
519 | return; |
520 | |
521 | blockSeriesSignals(); |
522 | if (q->orientation() == Qt::Horizontal) |
523 | insertData(start, end); |
524 | else if (start <= m_firstSetSection || start <= m_lastSetSection) |
525 | initializeCandlestickFromModel(); // if the changes affect the map - reinitialize |
526 | blockSeriesSignals(block: false); |
527 | } |
528 | |
529 | void QCandlestickModelMapperPrivate::modelColumnsRemoved(QModelIndex parent, int start, int end) |
530 | { |
531 | Q_UNUSED(parent) |
532 | |
533 | Q_Q(QCandlestickModelMapper); |
534 | |
535 | if (m_modelSignalsBlock) |
536 | return; |
537 | |
538 | blockSeriesSignals(); |
539 | if (q->orientation() == Qt::Horizontal) |
540 | removeData(start, end); |
541 | else if (start <= m_firstSetSection || start <= m_lastSetSection) |
542 | initializeCandlestickFromModel(); // if the changes affect the map - reinitialize |
543 | blockSeriesSignals(block: false); |
544 | } |
545 | |
546 | void QCandlestickModelMapperPrivate::modelDestroyed() |
547 | { |
548 | m_model = 0; |
549 | } |
550 | |
551 | void QCandlestickModelMapperPrivate::candlestickSetsAdded(const QList<QCandlestickSet *> &sets) |
552 | { |
553 | Q_Q(QCandlestickModelMapper); |
554 | |
555 | if (m_seriesSignalsBlock) |
556 | return; |
557 | |
558 | if (sets.isEmpty()) |
559 | return; |
560 | |
561 | int firstIndex = m_series->sets().indexOf(t: sets.at(i: 0)); |
562 | if (firstIndex == -1) |
563 | return; |
564 | |
565 | m_lastSetSection += sets.count(); |
566 | |
567 | blockModelSignals(); |
568 | if (q->orientation() == Qt::Vertical) |
569 | m_model->insertColumns(column: firstIndex + m_firstSetSection, count: sets.count()); |
570 | else |
571 | m_model->insertRows(row: firstIndex + m_firstSetSection, count: sets.count()); |
572 | |
573 | for (int i = 0; i < sets.count(); ++i) { |
574 | int section = i + firstIndex + m_firstSetSection; |
575 | m_model->setData(index: candlestickModelIndex(section, pos: m_timestamp), value: sets.at(i)->timestamp()); |
576 | m_model->setData(index: candlestickModelIndex(section, pos: m_open), value: sets.at(i)->open()); |
577 | m_model->setData(index: candlestickModelIndex(section, pos: m_high), value: sets.at(i)->high()); |
578 | m_model->setData(index: candlestickModelIndex(section, pos: m_low), value: sets.at(i)->low()); |
579 | m_model->setData(index: candlestickModelIndex(section, pos: m_close), value: sets.at(i)->close()); |
580 | } |
581 | blockModelSignals(block: false); |
582 | initializeCandlestickFromModel(); |
583 | } |
584 | |
585 | void QCandlestickModelMapperPrivate::candlestickSetsRemoved(const QList<QCandlestickSet *> &sets) |
586 | { |
587 | Q_Q(QCandlestickModelMapper); |
588 | |
589 | if (m_seriesSignalsBlock) |
590 | return; |
591 | |
592 | if (sets.isEmpty()) |
593 | return; |
594 | |
595 | QVector<int> removedIndices; |
596 | for (auto &set : sets) { |
597 | int index = m_sets.indexOf(t: set); |
598 | if (index != -1) |
599 | removedIndices << index; |
600 | } |
601 | |
602 | if (removedIndices.isEmpty()) |
603 | return; |
604 | |
605 | std::sort(first: removedIndices.begin(), last: removedIndices.end()); |
606 | |
607 | for (int i = removedIndices.size() - 1; i >= 0; --i) { |
608 | m_sets.removeAt(i: removedIndices[i]); |
609 | --m_lastSetSection; |
610 | } |
611 | |
612 | blockModelSignals(); |
613 | |
614 | // There is no guarantee removed sets are continuous, so remove them one by one |
615 | for (int i = removedIndices.size() - 1; i >= 0; --i) { |
616 | if (q->orientation() == Qt::Vertical) |
617 | m_model->removeColumns(column: removedIndices[i] + m_firstSetSection, count: 1); |
618 | else |
619 | m_model->removeRows(row: removedIndices[i] + m_firstSetSection, count: 1); |
620 | } |
621 | |
622 | blockModelSignals(block: false); |
623 | initializeCandlestickFromModel(); |
624 | } |
625 | |
626 | void QCandlestickModelMapperPrivate::candlestickSetChanged() |
627 | { |
628 | if (m_seriesSignalsBlock) |
629 | return; |
630 | |
631 | QCandlestickSet *set = qobject_cast<QCandlestickSet *>(object: QObject::sender()); |
632 | if (!set) |
633 | return; |
634 | |
635 | int section = m_series->sets().indexOf(t: set); |
636 | if (section < 0) |
637 | return; |
638 | |
639 | section += m_firstSetSection; |
640 | |
641 | blockModelSignals(); |
642 | m_model->setData(index: candlestickModelIndex(section, pos: m_timestamp), value: set->timestamp()); |
643 | m_model->setData(index: candlestickModelIndex(section, pos: m_open), value: set->open()); |
644 | m_model->setData(index: candlestickModelIndex(section, pos: m_high), value: set->high()); |
645 | m_model->setData(index: candlestickModelIndex(section, pos: m_low), value: set->low()); |
646 | m_model->setData(index: candlestickModelIndex(section, pos: m_close), value: set->close()); |
647 | blockModelSignals(block: false); |
648 | } |
649 | |
650 | void QCandlestickModelMapperPrivate::seriesDestroyed() |
651 | { |
652 | m_series = 0; |
653 | } |
654 | |
655 | QCandlestickSet *QCandlestickModelMapperPrivate::candlestickSet(QModelIndex index) |
656 | { |
657 | Q_Q(QCandlestickModelMapper); |
658 | |
659 | if (!index.isValid()) |
660 | return 0; |
661 | |
662 | int section = (q->orientation() == Qt::Vertical) ? index.column() : index.row(); |
663 | int pos = (q->orientation() == Qt::Vertical) ? index.row() : index.column(); |
664 | |
665 | if (section < m_firstSetSection || section > m_lastSetSection) |
666 | return 0; // This part of model has not been mapped to any candlestick set. |
667 | |
668 | if (pos != m_timestamp && pos != m_open && pos != m_high && pos != m_low && pos != m_close) |
669 | return 0; // This part of model has not been mapped to any candlestick set. |
670 | |
671 | return m_series->sets().at(i: section - m_firstSetSection); |
672 | } |
673 | |
674 | QModelIndex QCandlestickModelMapperPrivate::candlestickModelIndex(int section, int pos) |
675 | { |
676 | Q_Q(QCandlestickModelMapper); |
677 | |
678 | if (section < m_firstSetSection || section > m_lastSetSection) |
679 | return QModelIndex(); // invalid |
680 | |
681 | if (pos != m_timestamp && pos != m_open && pos != m_high && pos != m_low && pos != m_close) |
682 | return QModelIndex(); // invalid |
683 | |
684 | if (q->orientation() == Qt::Vertical) |
685 | return m_model->index(row: pos, column: section); |
686 | else |
687 | return m_model->index(row: section, column: pos); |
688 | } |
689 | |
690 | void QCandlestickModelMapperPrivate::insertData(int start, int end) |
691 | { |
692 | Q_UNUSED(start) |
693 | Q_UNUSED(end) |
694 | |
695 | // Currently candlestickchart needs to be fully recalculated when change is made. |
696 | initializeCandlestickFromModel(); |
697 | } |
698 | |
699 | void QCandlestickModelMapperPrivate::removeData(int start, int end) |
700 | { |
701 | Q_UNUSED(start) |
702 | Q_UNUSED(end) |
703 | |
704 | // Currently candlestickchart needs to be fully recalculated when change is made. |
705 | initializeCandlestickFromModel(); |
706 | } |
707 | |
708 | void QCandlestickModelMapperPrivate::blockModelSignals(bool block) |
709 | { |
710 | m_modelSignalsBlock = block; |
711 | } |
712 | |
713 | void QCandlestickModelMapperPrivate::blockSeriesSignals(bool block) |
714 | { |
715 | m_seriesSignalsBlock = block; |
716 | } |
717 | |
718 | QT_CHARTS_END_NAMESPACE |
719 | |
720 | #include "moc_qcandlestickmodelmapper.cpp" |
721 | #include "moc_qcandlestickmodelmapper_p.cpp" |
722 | |