##// END OF EJS Templates
QXYModelMapper: Handle model reset....
Christian Kandeler -
r2773:7a4cd1d34c08
parent child
Show More
@@ -1,531 +1,532
1 1 /****************************************************************************
2 2 **
3 3 ** Copyright (C) 2014 Digia Plc
4 4 ** All rights reserved.
5 5 ** For any questions to Digia, please use contact form at http://qt.io
6 6 **
7 7 ** This file is part of the Qt Charts module.
8 8 **
9 9 ** Licensees holding valid commercial license for Qt may use this file in
10 10 ** accordance with the Qt License Agreement provided with the Software
11 11 ** or, alternatively, in accordance with the terms contained in a written
12 12 ** agreement between you and Digia.
13 13 **
14 14 ** If you have questions regarding the use of this file, please use
15 15 ** contact form at http://qt.io
16 16 **
17 17 ****************************************************************************/
18 18
19 19 #include <QtCharts/QXYModelMapper>
20 20 #include <private/qxymodelmapper_p.h>
21 21 #include <QtCharts/QXYSeries>
22 22 #include <QtCore/QAbstractItemModel>
23 23 #include <QtCore/QDateTime>
24 24
25 25 QT_CHARTS_BEGIN_NAMESPACE
26 26
27 27 /*!
28 28 Constructs a mapper object which is a child of \a parent.
29 29 */
30 30 QXYModelMapper::QXYModelMapper(QObject *parent)
31 31 : QObject(parent),
32 32 d_ptr(new QXYModelMapperPrivate(this))
33 33 {
34 34 }
35 35
36 36 /*!
37 37 \internal
38 38 */
39 39 QAbstractItemModel *QXYModelMapper::model() const
40 40 {
41 41 Q_D(const QXYModelMapper);
42 42 return d->m_model;
43 43 }
44 44
45 45 /*!
46 46 \internal
47 47 */
48 48 void QXYModelMapper::setModel(QAbstractItemModel *model)
49 49 {
50 50 if (model == 0)
51 51 return;
52 52
53 53 Q_D(QXYModelMapper);
54 54 if (d->m_model)
55 55 disconnect(d->m_model, 0, d, 0);
56 56
57 57 d->m_model = model;
58 58 d->initializeXYFromModel();
59 59 // connect signals from the model
60 60 connect(d->m_model, SIGNAL(dataChanged(QModelIndex,QModelIndex)), d, SLOT(modelUpdated(QModelIndex,QModelIndex)));
61 61 connect(d->m_model, SIGNAL(rowsInserted(QModelIndex,int,int)), d, SLOT(modelRowsAdded(QModelIndex,int,int)));
62 62 connect(d->m_model, SIGNAL(rowsRemoved(QModelIndex,int,int)), d, SLOT(modelRowsRemoved(QModelIndex,int,int)));
63 63 connect(d->m_model, SIGNAL(columnsInserted(QModelIndex,int,int)), d, SLOT(modelColumnsAdded(QModelIndex,int,int)));
64 64 connect(d->m_model, SIGNAL(columnsRemoved(QModelIndex,int,int)), d, SLOT(modelColumnsRemoved(QModelIndex,int,int)));
65 connect(d->m_model, SIGNAL(modelReset()), d, SLOT(initializeXYFromModel()));
65 66 connect(d->m_model, SIGNAL(destroyed()), d, SLOT(handleModelDestroyed()));
66 67 }
67 68
68 69 /*!
69 70 \internal
70 71 */
71 72 QXYSeries *QXYModelMapper::series() const
72 73 {
73 74 Q_D(const QXYModelMapper);
74 75 return d->m_series;
75 76 }
76 77
77 78 /*!
78 79 \internal
79 80 */
80 81 void QXYModelMapper::setSeries(QXYSeries *series)
81 82 {
82 83 Q_D(QXYModelMapper);
83 84 if (d->m_series)
84 85 disconnect(d->m_series, 0, d, 0);
85 86
86 87 if (series == 0)
87 88 return;
88 89
89 90 d->m_series = series;
90 91 d->initializeXYFromModel();
91 92 // connect the signals from the series
92 93 connect(d->m_series, SIGNAL(pointAdded(int)), d, SLOT(handlePointAdded(int)));
93 94 connect(d->m_series, SIGNAL(pointRemoved(int)), d, SLOT(handlePointRemoved(int)));
94 95 connect(d->m_series, SIGNAL(pointReplaced(int)), d, SLOT(handlePointReplaced(int)));
95 96 connect(d->m_series, SIGNAL(destroyed()), d, SLOT(handleSeriesDestroyed()));
96 97 }
97 98
98 99 /*!
99 100 \internal
100 101 */
101 102 int QXYModelMapper::first() const
102 103 {
103 104 Q_D(const QXYModelMapper);
104 105 return d->m_first;
105 106 }
106 107
107 108 /*!
108 109 \internal
109 110 */
110 111 void QXYModelMapper::setFirst(int first)
111 112 {
112 113 Q_D(QXYModelMapper);
113 114 d->m_first = qMax(first, 0);
114 115 d->initializeXYFromModel();
115 116 }
116 117
117 118 /*!
118 119 \internal
119 120 */
120 121 int QXYModelMapper::count() const
121 122 {
122 123 Q_D(const QXYModelMapper);
123 124 return d->m_count;
124 125 }
125 126
126 127 /*!
127 128 \internal
128 129 */
129 130 void QXYModelMapper::setCount(int count)
130 131 {
131 132 Q_D(QXYModelMapper);
132 133 d->m_count = qMax(count, -1);
133 134 d->initializeXYFromModel();
134 135 }
135 136
136 137 /*!
137 138 Returns the orientation that is used when QXYModelMapper accesses the model.
138 139 This mean whether the consecutive x/y values of the QXYSeries are read from rows (Qt::Horizontal)
139 140 or from columns (Qt::Vertical)
140 141 */
141 142 Qt::Orientation QXYModelMapper::orientation() const
142 143 {
143 144 Q_D(const QXYModelMapper);
144 145 return d->m_orientation;
145 146 }
146 147
147 148 /*!
148 149 Returns the \a orientation that is used when QXYModelMapper accesses the model.
149 150 This mean whether the consecutive x/y values of the QXYSeries are read from rows (Qt::Horizontal)
150 151 or from columns (Qt::Vertical)
151 152 */
152 153 void QXYModelMapper::setOrientation(Qt::Orientation orientation)
153 154 {
154 155 Q_D(QXYModelMapper);
155 156 d->m_orientation = orientation;
156 157 d->initializeXYFromModel();
157 158 }
158 159
159 160 /*!
160 161 Returns which section of the model is kept in sync with the x values of the QXYSeries
161 162 */
162 163 int QXYModelMapper::xSection() const
163 164 {
164 165 Q_D(const QXYModelMapper);
165 166 return d->m_xSection;
166 167 }
167 168
168 169 /*!
169 170 Sets the model section that is kept in sync with the x values of the QXYSeries.
170 171 Parameter \a xSection specifies the section of the model.
171 172 */
172 173 void QXYModelMapper::setXSection(int xSection)
173 174 {
174 175 Q_D(QXYModelMapper);
175 176 d->m_xSection = qMax(-1, xSection);
176 177 d->initializeXYFromModel();
177 178 }
178 179
179 180 /*!
180 181 Returns which section of the model is kept in sync with the y values of the QXYSeries
181 182 */
182 183 int QXYModelMapper::ySection() const
183 184 {
184 185 Q_D(const QXYModelMapper);
185 186 return d->m_ySection;
186 187 }
187 188
188 189 /*!
189 190 Sets the model section that is kept in sync with the y values of the QXYSeries.
190 191 Parameter \a ySection specifies the section of the model.
191 192 */
192 193 void QXYModelMapper::setYSection(int ySection)
193 194 {
194 195 Q_D(QXYModelMapper);
195 196 d->m_ySection = qMax(-1, ySection);
196 197 d->initializeXYFromModel();
197 198 }
198 199
199 200 ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
200 201
201 202 QXYModelMapperPrivate::QXYModelMapperPrivate(QXYModelMapper *q) :
202 203 QObject(q),
203 204 m_series(0),
204 205 m_model(0),
205 206 m_first(0),
206 207 m_count(-1),
207 208 m_orientation(Qt::Vertical),
208 209 m_xSection(-1),
209 210 m_ySection(-1),
210 211 m_seriesSignalsBlock(false),
211 212 m_modelSignalsBlock(false),
212 213 q_ptr(q)
213 214 {
214 215 }
215 216
216 217 void QXYModelMapperPrivate::blockModelSignals(bool block)
217 218 {
218 219 m_modelSignalsBlock = block;
219 220 }
220 221
221 222 void QXYModelMapperPrivate::blockSeriesSignals(bool block)
222 223 {
223 224 m_seriesSignalsBlock = block;
224 225 }
225 226
226 227 QModelIndex QXYModelMapperPrivate::xModelIndex(int xPos)
227 228 {
228 229 if (m_count != -1 && xPos >= m_count)
229 230 return QModelIndex(); // invalid
230 231
231 232 if (m_orientation == Qt::Vertical)
232 233 return m_model->index(xPos + m_first, m_xSection);
233 234 else
234 235 return m_model->index(m_xSection, xPos + m_first);
235 236 }
236 237
237 238 QModelIndex QXYModelMapperPrivate::yModelIndex(int yPos)
238 239 {
239 240 if (m_count != -1 && yPos >= m_count)
240 241 return QModelIndex(); // invalid
241 242
242 243 if (m_orientation == Qt::Vertical)
243 244 return m_model->index(yPos + m_first, m_ySection);
244 245 else
245 246 return m_model->index(m_ySection, yPos + m_first);
246 247 }
247 248
248 249 qreal QXYModelMapperPrivate::valueFromModel(QModelIndex index)
249 250 {
250 251 QVariant value = m_model->data(index, Qt::DisplayRole);
251 252 switch (value.type()) {
252 253 case QVariant::DateTime:
253 254 return value.toDateTime().toMSecsSinceEpoch();
254 255 case QVariant::Date:
255 256 return QDateTime(value.toDate()).toMSecsSinceEpoch();
256 257 default:
257 258 return value.toReal();
258 259 }
259 260 }
260 261
261 262 void QXYModelMapperPrivate::setValueToModel(QModelIndex index, qreal value)
262 263 {
263 264 QVariant oldValue = m_model->data(index, Qt::DisplayRole);
264 265 switch (oldValue.type()) {
265 266 case QVariant::DateTime:
266 267 m_model->setData(index, QDateTime::fromMSecsSinceEpoch(value));
267 268 break;
268 269 case QVariant::Date:
269 270 m_model->setData(index, QDateTime::fromMSecsSinceEpoch(value).date());
270 271 break;
271 272 default:
272 273 m_model->setData(index, value);
273 274 }
274 275 }
275 276
276 277 void QXYModelMapperPrivate::handlePointAdded(int pointPos)
277 278 {
278 279 if (m_seriesSignalsBlock)
279 280 return;
280 281
281 282 if (m_count != -1)
282 283 m_count += 1;
283 284
284 285 blockModelSignals();
285 286 if (m_orientation == Qt::Vertical)
286 287 m_model->insertRows(pointPos + m_first, 1);
287 288 else
288 289 m_model->insertColumns(pointPos + m_first, 1);
289 290
290 291 setValueToModel(xModelIndex(pointPos), m_series->points().at(pointPos).x());
291 292 setValueToModel(yModelIndex(pointPos), m_series->points().at(pointPos).y());
292 293 blockModelSignals(false);
293 294 }
294 295
295 296 void QXYModelMapperPrivate::handlePointRemoved(int pointPos)
296 297 {
297 298 if (m_seriesSignalsBlock)
298 299 return;
299 300
300 301 if (m_count != -1)
301 302 m_count -= 1;
302 303
303 304 blockModelSignals();
304 305 if (m_orientation == Qt::Vertical)
305 306 m_model->removeRow(pointPos + m_first);
306 307 else
307 308 m_model->removeColumn(pointPos + m_first);
308 309 blockModelSignals(false);
309 310 }
310 311
311 312 void QXYModelMapperPrivate::handlePointReplaced(int pointPos)
312 313 {
313 314 if (m_seriesSignalsBlock)
314 315 return;
315 316
316 317 blockModelSignals();
317 318 setValueToModel(xModelIndex(pointPos), m_series->points().at(pointPos).x());
318 319 setValueToModel(yModelIndex(pointPos), m_series->points().at(pointPos).y());
319 320 blockModelSignals(false);
320 321 }
321 322
322 323 void QXYModelMapperPrivate::handleSeriesDestroyed()
323 324 {
324 325 m_series = 0;
325 326 }
326 327
327 328 void QXYModelMapperPrivate::modelUpdated(QModelIndex topLeft, QModelIndex bottomRight)
328 329 {
329 330 if (m_model == 0 || m_series == 0)
330 331 return;
331 332
332 333 if (m_modelSignalsBlock)
333 334 return;
334 335
335 336 blockSeriesSignals();
336 337 QModelIndex index;
337 338 QPointF oldPoint;
338 339 QPointF newPoint;
339 340 for (int row = topLeft.row(); row <= bottomRight.row(); row++) {
340 341 for (int column = topLeft.column(); column <= bottomRight.column(); column++) {
341 342 index = topLeft.sibling(row, column);
342 343 if (m_orientation == Qt::Vertical && (index.column() == m_xSection || index.column() == m_ySection)) {
343 344 if (index.row() >= m_first && (m_count == - 1 || index.row() < m_first + m_count)) {
344 345 QModelIndex xIndex = xModelIndex(index.row() - m_first);
345 346 QModelIndex yIndex = yModelIndex(index.row() - m_first);
346 347 if (xIndex.isValid() && yIndex.isValid()) {
347 348 oldPoint = m_series->points().at(index.row() - m_first);
348 349 newPoint.setX(valueFromModel(xIndex));
349 350 newPoint.setY(valueFromModel(yIndex));
350 351 }
351 352 }
352 353 } else if (m_orientation == Qt::Horizontal && (index.row() == m_xSection || index.row() == m_ySection)) {
353 354 if (index.column() >= m_first && (m_count == - 1 || index.column() < m_first + m_count)) {
354 355 QModelIndex xIndex = xModelIndex(index.column() - m_first);
355 356 QModelIndex yIndex = yModelIndex(index.column() - m_first);
356 357 if (xIndex.isValid() && yIndex.isValid()) {
357 358 oldPoint = m_series->points().at(index.column() - m_first);
358 359 newPoint.setX(valueFromModel(xIndex));
359 360 newPoint.setY(valueFromModel(yIndex));
360 361 }
361 362 }
362 363 } else {
363 364 continue;
364 365 }
365 366 m_series->replace(oldPoint, newPoint);
366 367 }
367 368 }
368 369 blockSeriesSignals(false);
369 370 }
370 371
371 372 void QXYModelMapperPrivate::modelRowsAdded(QModelIndex parent, int start, int end)
372 373 {
373 374 Q_UNUSED(parent);
374 375 if (m_modelSignalsBlock)
375 376 return;
376 377
377 378 blockSeriesSignals();
378 379 if (m_orientation == Qt::Vertical)
379 380 insertData(start, end);
380 381 else if (start <= m_xSection || start <= m_ySection) // if the changes affect the map - reinitialize the xy
381 382 initializeXYFromModel();
382 383 blockSeriesSignals(false);
383 384 }
384 385
385 386 void QXYModelMapperPrivate::modelRowsRemoved(QModelIndex parent, int start, int end)
386 387 {
387 388 Q_UNUSED(parent);
388 389 if (m_modelSignalsBlock)
389 390 return;
390 391
391 392 blockSeriesSignals();
392 393 if (m_orientation == Qt::Vertical)
393 394 removeData(start, end);
394 395 else if (start <= m_xSection || start <= m_ySection) // if the changes affect the map - reinitialize the xy
395 396 initializeXYFromModel();
396 397 blockSeriesSignals(false);
397 398 }
398 399
399 400 void QXYModelMapperPrivate::modelColumnsAdded(QModelIndex parent, int start, int end)
400 401 {
401 402 Q_UNUSED(parent);
402 403 if (m_modelSignalsBlock)
403 404 return;
404 405
405 406 blockSeriesSignals();
406 407 if (m_orientation == Qt::Horizontal)
407 408 insertData(start, end);
408 409 else if (start <= m_xSection || start <= m_ySection) // if the changes affect the map - reinitialize the xy
409 410 initializeXYFromModel();
410 411 blockSeriesSignals(false);
411 412 }
412 413
413 414 void QXYModelMapperPrivate::modelColumnsRemoved(QModelIndex parent, int start, int end)
414 415 {
415 416 Q_UNUSED(parent);
416 417 if (m_modelSignalsBlock)
417 418 return;
418 419
419 420 blockSeriesSignals();
420 421 if (m_orientation == Qt::Horizontal)
421 422 removeData(start, end);
422 423 else if (start <= m_xSection || start <= m_ySection) // if the changes affect the map - reinitialize the xy
423 424 initializeXYFromModel();
424 425 blockSeriesSignals(false);
425 426 }
426 427
427 428 void QXYModelMapperPrivate::handleModelDestroyed()
428 429 {
429 430 m_model = 0;
430 431 }
431 432
432 433 void QXYModelMapperPrivate::insertData(int start, int end)
433 434 {
434 435 if (m_model == 0 || m_series == 0)
435 436 return;
436 437
437 438 if (m_count != -1 && start >= m_first + m_count) {
438 439 return;
439 440 } else {
440 441 int addedCount = end - start + 1;
441 442 if (m_count != -1 && addedCount > m_count)
442 443 addedCount = m_count;
443 444 int first = qMax(start, m_first);
444 445 int last = qMin(first + addedCount - 1, m_orientation == Qt::Vertical ? m_model->rowCount() - 1 : m_model->columnCount() - 1);
445 446 for (int i = first; i <= last; i++) {
446 447 QPointF point;
447 448 QModelIndex xIndex = xModelIndex(i - m_first);
448 449 QModelIndex yIndex = yModelIndex(i - m_first);
449 450 if (xIndex.isValid() && yIndex.isValid()) {
450 451 point.setX(valueFromModel(xIndex));
451 452 point.setY(valueFromModel(yIndex));
452 453 m_series->insert(i - m_first, point);
453 454 }
454 455 }
455 456
456 457 // remove excess of points (above m_count)
457 458 if (m_count != -1 && m_series->points().size() > m_count)
458 459 for (int i = m_series->points().size() - 1; i >= m_count; i--) {
459 460 m_series->remove(m_series->points().at(i));
460 461 }
461 462 }
462 463 }
463 464
464 465 void QXYModelMapperPrivate::removeData(int start, int end)
465 466 {
466 467 if (m_model == 0 || m_series == 0)
467 468 return;
468 469
469 470 int removedCount = end - start + 1;
470 471 if (m_count != -1 && start >= m_first + m_count) {
471 472 return;
472 473 } else {
473 474 int toRemove = qMin(m_series->count(), removedCount); // first find how many items can actually be removed
474 475 int first = qMax(start, m_first); // get the index of the first item that will be removed.
475 476 int last = qMin(first + toRemove - 1, m_series->count() + m_first - 1); // get the index of the last item that will be removed.
476 477 for (int i = last; i >= first; i--) {
477 478 m_series->remove(m_series->points().at(i - m_first));
478 479 }
479 480
480 481 if (m_count != -1) {
481 482 int itemsAvailable; // check how many are available to be added
482 483 if (m_orientation == Qt::Vertical)
483 484 itemsAvailable = m_model->rowCount() - m_first - m_series->count();
484 485 else
485 486 itemsAvailable = m_model->columnCount() - m_first - m_series->count();
486 487 int toBeAdded = qMin(itemsAvailable, m_count - m_series->count()); // add not more items than there is space left to be filled.
487 488 int currentSize = m_series->count();
488 489 if (toBeAdded > 0)
489 490 for (int i = m_series->count(); i < currentSize + toBeAdded; i++) {
490 491 QPointF point;
491 492 QModelIndex xIndex = xModelIndex(i);
492 493 QModelIndex yIndex = yModelIndex(i);
493 494 if (xIndex.isValid() && yIndex.isValid()) {
494 495 point.setX(valueFromModel(xIndex));
495 496 point.setY(valueFromModel(yIndex));
496 497 m_series->insert(i, point);
497 498 }
498 499 }
499 500 }
500 501 }
501 502 }
502 503
503 504 void QXYModelMapperPrivate::initializeXYFromModel()
504 505 {
505 506 if (m_model == 0 || m_series == 0)
506 507 return;
507 508
508 509 blockSeriesSignals();
509 510 // clear current content
510 511 m_series->clear();
511 512
512 513 // create the initial points set
513 514 int pointPos = 0;
514 515 QModelIndex xIndex = xModelIndex(pointPos);
515 516 QModelIndex yIndex = yModelIndex(pointPos);
516 517 while (xIndex.isValid() && yIndex.isValid()) {
517 518 QPointF point;
518 519 point.setX(valueFromModel(xIndex));
519 520 point.setY(valueFromModel(yIndex));
520 521 m_series->append(point);
521 522 pointPos++;
522 523 xIndex = xModelIndex(pointPos);
523 524 yIndex = yModelIndex(pointPos);
524 525 }
525 526 blockSeriesSignals(false);
526 527 }
527 528
528 529 #include "moc_qxymodelmapper.cpp"
529 530 #include "moc_qxymodelmapper_p.cpp"
530 531
531 532 QT_CHARTS_END_NAMESPACE
General Comments 0
You need to be logged in to leave comments. Login now