1// Copyright (C) 2023 The Qt Company Ltd.
2// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only
3
4#include "baritemmodelhandler_p.h"
5#include "qitemmodelbardataproxy_p.h"
6#include "qgraphs3dlogging_p.h"
7
8QT_BEGIN_NAMESPACE
9
10/*!
11 * \class QItemModelBarDataProxy
12 * \inmodule QtGraphs
13 * \ingroup graphs_3D
14 * \brief Proxy class for presenting data in item models with Q3DBarsWidgetItem.
15 *
16 * QItemModelBarDataProxy allows you to use QAbstractItemModel derived models as
17 * a data source for Q3DBarsWidgetItem. It uses the defined mappings to map data from the
18 * model to rows, columns, and values of Q3DBarsWidgetItem graph.
19 *
20 * The data is resolved asynchronously whenever mappings or the model changes.
21 * QBarDataProxy::arrayReset() is emitted when the data has been resolved.
22 * However, when useModelCategories property is set to true, single item changes
23 * are resolved synchronously, unless the same frame also contains a change that
24 * causes the whole model to be resolved.
25 *
26 * Mappings can be used in the following ways:
27 *
28 * \list
29 * \li If useModelCategories property is set to true, this proxy will map rows and
30 * columns of QAbstractItemModel directly to rows and columns of Q3DBarsWidgetItem, and uses the value
31 * returned for Qt::DisplayRole as bar value by default.
32 * The value role to be used can be redefined if Qt::DisplayRole is not suitable.
33 *
34 * \li For models that do not have data already neatly sorted into rows and columns, such as
35 * QAbstractListModel based models, you can define a role from the model to map for each of the
36 * row, column and value.
37 *
38 * \li If you do not want to include all data contained in the model, or the autogenerated rows and
39 * columns are not ordered as you wish, you can specify which rows and columns should be included
40 * and in which order by defining an explicit list of categories for either or both of rows and
41 * columns.
42 * \endlist
43 *
44 * For example, assume that you have a custom QAbstractItemModel for storing various monthly values
45 * related to a business.
46 * Each item in the model has the roles "year", "month", "income", and "expenses".
47 * You could do the following to display the data in a bar graph:
48 *
49 * \snippet doc_src_qtgraphs.cpp barmodelproxy
50 *
51 * If the fields of the model do not contain the data in the exact format you
52 * need, you can specify a search pattern regular expression and a replace rule
53 * for each role to get the value in a format you need. For more information on how
54 * the replacement using regular expressions works, see QString::replace(const
55 * QRegularExpression &rx, const QString &after) function documentation. Note
56 * that using regular expressions has an impact on the performance, so it's more
57 * efficient to utilize item models where doing search and replace is not
58 * necessary to get the desired values.
59 *
60 * For example about using the search patterns in conjunction with the roles,
61 * see \l{Simple Bar Graph}.
62 *
63 * \sa {Qt Graphs Data Handling with 3D}
64 */
65
66/*!
67 * \qmltype ItemModelBarDataProxy
68 * \inqmlmodule QtGraphs
69 * \ingroup graphs_qml_3D
70 * \nativetype QItemModelBarDataProxy
71 * \inherits BarDataProxy
72 * \brief Proxy class for presenting data in item models with Bars3D.
73 *
74 * This type allows you to use AbstractItemModel derived models as a data source
75 * for Bars3D.
76 *
77 * Data is resolved asynchronously whenever the mapping or the model changes.
78 * QBarDataProxy::arrayReset() is emitted when the data has been resolved.
79 *
80 * For ItemModelBarDataProxy enums, see
81 * \l{QItemModelBarDataProxy::MultiMatchBehavior}.
82 *
83 * For more details, see QItemModelBarDataProxy documentation.
84 *
85 * Usage example:
86 *
87 * \snippet doc_src_qmlgraphs.cpp 7
88 *
89 * \sa BarDataProxy, {Qt Graphs Data Handling with 3D}
90 */
91
92/*!
93 * \qmlproperty model ItemModelBarDataProxy::itemModel
94 * The item model.
95 */
96
97/*!
98 * \qmlproperty string ItemModelBarDataProxy::rowRole
99 * The item model role to map into row category.
100 */
101
102/*!
103 * \qmlproperty string ItemModelBarDataProxy::columnRole
104 * The item model role to map into column category.
105 */
106
107/*!
108 * \qmlproperty string ItemModelBarDataProxy::valueRole
109 * The item model role to map into bar value.
110 */
111
112/*!
113 * \qmlproperty string ItemModelBarDataProxy::rotationRole
114 * The item model role to map into bar rotation angle.
115 */
116
117/*!
118 * \qmlproperty list<String> ItemModelBarDataProxy::rowCategories
119 * The row categories of the mapping. Only items with row role values that are
120 * found in this list are included when the data is resolved. The rows are
121 * ordered in the same order as they are in this list.
122 */
123
124/*!
125 * \qmlproperty list<String> ItemModelBarDataProxy::columnCategories
126 * The column categories of the mapping. Only items with column role values that
127 * are found in this list are included when the data is resolved. The columns
128 * are ordered in the same order as they are in this list.
129 */
130
131/*!
132 * \qmlproperty bool ItemModelBarDataProxy::useModelCategories
133 * When set to \c true, the mapping ignores row and column roles and categories,
134 * and uses the rows and columns from the model instead. Row and column headers
135 * are used for row and column labels. Defaults to \c{false}.
136 */
137
138/*!
139 * \qmlproperty bool ItemModelBarDataProxy::autoRowCategories
140 * When set to \c true, the mapping ignores any explicitly set row categories
141 * and overwrites them with automatically generated ones whenever the
142 * data from the model is resolved. Defaults to \c{true}.
143 */
144
145/*!
146 * \qmlproperty bool ItemModelBarDataProxy::autoColumnCategories
147 * When set to \c true, the mapping ignores any explicitly set column categories
148 * and overwrites them with automatically generated ones whenever the
149 * data from model is resolved. Defaults to \c{true}.
150 */
151
152/*!
153 * \qmlproperty regExp ItemModelBarDataProxy::rowRolePattern
154 * When set, a search and replace is done on the value mapped by row role before
155 * it is used as a row category. This property specifies the regular expression
156 * to find the portion of the mapped value to replace and rowRoleReplace
157 * property contains the replacement string. This is useful for example in
158 * parsing row and column categories from a single timestamp field in the item
159 * model.
160 *
161 * \sa rowRole, rowRoleReplace
162 */
163
164/*!
165 * \qmlproperty regExp ItemModelBarDataProxy::columnRolePattern
166 * When set, a search and replace is done on the value mapped by column role
167 * before it is used as a column category. This property specifies the regular
168 * expression to find the portion of the mapped value to replace and
169 * columnRoleReplace property contains the replacement string. This is useful
170 * for example in parsing row and column categories from a single timestamp
171 * field in the item model.
172 *
173 * \sa columnRole, columnRoleReplace
174 */
175
176/*!
177 * \qmlproperty regExp ItemModelBarDataProxy::valueRolePattern
178 * When set, a search and replace is done on the value mapped by value role
179 * before it is used as a bar value. This property specifies the regular
180 * expression to find the portion of the mapped value to replace and
181 * valueRoleReplace property contains the replacement string.
182 *
183 * \sa valueRole, valueRoleReplace
184 */
185
186/*!
187 * \qmlproperty regExp ItemModelBarDataProxy::rotationRolePattern
188 * When set, a search and replace is done on the value mapped by rotation role
189 * before it is used as a bar rotation angle. This property specifies the
190 * regular expression to find the portion of the mapped value to replace and
191 * rotationRoleReplace property contains the replacement string.
192 *
193 * \sa rotationRole, rotationRoleReplace
194 */
195
196/*!
197 * \qmlproperty string ItemModelBarDataProxy::rowRoleReplace
198 * This property defines the replacement content to be used in conjunction with
199 * rowRolePattern. Defaults to empty string. For more information on how the
200 * search and replace using regular expressions works, see
201 * QString::replace(const QRegularExpression &rx, const QString &after) function
202 * documentation.
203 *
204 * \sa rowRole, rowRolePattern
205 */
206
207/*!
208 * \qmlproperty string ItemModelBarDataProxy::columnRoleReplace
209 * This property defines the replacement content to be used in conjunction with
210 * columnRolePattern. Defaults to empty string. For more information on how the
211 * search and replace using regular expressions works, see
212 * QString::replace(const QRegularExpression &rx, const QString &after) function
213 * documentation.
214 *
215 * \sa columnRole, columnRolePattern
216 */
217
218/*!
219 * \qmlproperty string ItemModelBarDataProxy::valueRoleReplace
220 * This property defines the replacement content to be used in conjunction with
221 * valueRolePattern. Defaults to empty string. For more information on how the
222 * search and replace using regular expressions works, see
223 * QString::replace(const QRegularExpression &rx, const QString &after) function
224 * documentation.
225 *
226 * \sa valueRole, valueRolePattern
227 */
228
229/*!
230 * \qmlproperty string ItemModelBarDataProxy::rotationRoleReplace
231 * This property defines the replacement content to be used in conjunction with
232 * rotationRolePattern. Defaults to empty string. For more information on how
233 * the search and replace using regular expressions works, see
234 * QString::replace(const QRegularExpression &rx, const QString &after) function
235 * documentation.
236 *
237 * \sa rotationRole, rotationRolePattern
238 */
239
240/*!
241 * \qmlproperty enumeration ItemModelBarDataProxy::multiMatchBehavior
242 * Defines how multiple matches for each row/column combination are handled.
243 * Defaults to
244 * \l{QItemModelBarDataProxy::MultiMatchBehavior::Last}
245 * {ItemModelBarDataProxy.MultiMatchBehavior.Last}.
246 * The chosen behavior affects both bar value and rotation.
247 *
248 * For example, you might have an item model with timestamped data taken at
249 * irregular intervals and you want to visualize total value of data items on
250 * each day with a bar graph. This can be done by specifying row and column
251 * categories so that each bar represents a day, and setting multiMatchBehavior
252 * to
253 * \l{QItemModelBarDataProxy::MultiMatchBehavior::Cumulative}
254 * {ItemModelBarDataProxy.MultiMatchBehavior.Cumulative}.
255 */
256
257/*!
258 \qmlsignal ItemModelBarDataProxy::itemModelChanged(model itemModel)
259
260 This signal is emitted when itemModel changes to \a itemModel.
261*/
262/*!
263 \qmlsignal ItemModelBarDataProxy::rowRoleChanged(string role)
264
265 This signal is emitted when rowRole changes to \a role.
266*/
267/*!
268 \qmlsignal ItemModelBarDataProxy::columnRoleChanged(string role)
269
270 This signal is emitted when columnRole changes to \a role.
271*/
272/*!
273 \qmlsignal ItemModelBarDataProxy::valueRoleChanged(string role)
274
275 This signal is emitted when valueRole changes to \a role.
276*/
277/*!
278 \qmlsignal ItemModelBarDataProxy::rotationRoleChanged(string role)
279
280 This signal is emitted when rotationRole changes to \a role.
281*/
282/*!
283 \qmlsignal ItemModelBarDataProxy::rowCategoriesChanged()
284
285 This signal is emitted when rowCategories changes.
286*/
287/*!
288 \qmlsignal ItemModelBarDataProxy::columnCategoriesChanged()
289
290 This signal is emitted when columnCategories changes.
291*/
292/*!
293 \qmlsignal ItemModelBarDataProxy::useModelCategoriesChanged(bool enable)
294
295 This signal is emitted when useModelCategories changes to \a enable.
296*/
297/*!
298 \qmlsignal ItemModelBarDataProxy::autoRowCategoriesChanged(bool enable)
299
300 This signal is emitted when autoRowCategories changes to \a enable.
301*/
302/*!
303 \qmlsignal ItemModelBarDataProxy::autoColumnCategoriesChanged(bool enable)
304
305 This signal is emitted when autoColumnCategories changes to \a enable.
306*/
307/*!
308 \qmlsignal ItemModelBarDataProxy::rowRolePatternChanged(regExp pattern)
309
310 This signal is emitted when rowRolePattern changes to \a pattern.
311*/
312/*!
313 \qmlsignal ItemModelBarDataProxy::columnRolePatternChanged(regExp pattern)
314
315 This signal is emitted when columnRolePattern changes to \a pattern.
316*/
317/*!
318 \qmlsignal ItemModelBarDataProxy::valueRolePatternChanged(regExp pattern)
319
320 This signal is emitted when valueRolePattern changes to \a pattern.
321*/
322/*!
323 \qmlsignal ItemModelBarDataProxy::rotationRolePatternChanged(regExp pattern)
324
325 This signal is emitted when rotationRolePattern changes to \a pattern.
326*/
327/*!
328 \qmlsignal ItemModelBarDataProxy::rowRoleReplaceChanged(string replace)
329
330 This signal is emitted when rowRoleReplace changes to \a replace.
331*/
332/*!
333 \qmlsignal ItemModelBarDataProxy::columnRoleReplaceChanged(string replace)
334
335 This signal is emitted when columnRoleReplace changes to \a replace.
336*/
337/*!
338 \qmlsignal ItemModelBarDataProxy::valueRoleReplaceChanged(string replace)
339
340 This signal is emitted when valueRoleReplace changes to \a replace.
341*/
342/*!
343 \qmlsignal ItemModelBarDataProxy::rotationRoleReplaceChanged(string replace)
344
345 This signal is emitted when rotationRoleReplace changes to \a replace.
346*/
347/*!
348 \qmlsignal ItemModelBarDataProxy::multiMatchBehaviorChanged(enumeration behavior)
349
350 This signal is emitted when multiMatchBehavior changes to \a behavior.
351*/
352
353/*!
354 * \enum QItemModelBarDataProxy::MultiMatchBehavior
355 *
356 * Behavior types for QItemModelBarDataProxy::multiMatchBehavior property.
357 *
358 * \value First
359 * The value is taken from the first item in the item model that matches
360 * each row/column combination.
361 * \value Last
362 * The value is taken from the last item in the item model that matches
363 * each row/column combination.
364 * \value Average
365 * The values from all items matching each row/column combination are
366 * averaged together and the average is used as the bar value.
367 * \value Cumulative
368 * The values from all items matching each row/column combination are
369 * added together and the total is used as the bar value.
370 */
371
372/*!
373 * Constructs QItemModelBarDataProxy with an optional \a parent.
374 */
375QItemModelBarDataProxy::QItemModelBarDataProxy(QObject *parent)
376 : QBarDataProxy(*(new QItemModelBarDataProxyPrivate(this)), parent)
377{
378 Q_D(QItemModelBarDataProxy);
379 d->connectItemModelHandler();
380}
381
382/*!
383 * Constructs QItemModelBarDataProxy with \a itemModel and an optional \a parent.
384 * The proxy doesn't take ownership of the \a itemModel, as typically item models
385 * are owned by other controls.
386 */
387QItemModelBarDataProxy::QItemModelBarDataProxy(QAbstractItemModel *itemModel, QObject *parent)
388 : QBarDataProxy(*(new QItemModelBarDataProxyPrivate(this)), parent)
389{
390 Q_D(QItemModelBarDataProxy);
391 setItemModel(itemModel);
392 d->connectItemModelHandler();
393}
394
395/*!
396 * Constructs QItemModelBarDataProxy with \a itemModel and an optional \a parent.
397 * The proxy doesn't take ownership of the \a itemModel, as typically item models
398 * are owned by other controls. The value role is set to \a valueRole. This
399 * constructor is meant to be used with models that have data properly sorted in
400 * rows and columns already, so it also sets useModelCategories property to
401 * true.
402 */
403QItemModelBarDataProxy::QItemModelBarDataProxy(QAbstractItemModel *itemModel,
404 const QString &valueRole,
405 QObject *parent)
406 : QBarDataProxy(*(new QItemModelBarDataProxyPrivate(this)), parent)
407{
408 Q_D(QItemModelBarDataProxy);
409 d->m_itemModelHandler->setItemModel(itemModel);
410 d->m_valueRole = valueRole;
411 d->m_useModelCategories = true;
412 d->connectItemModelHandler();
413}
414
415/*!
416 * Constructs QItemModelBarDataProxy with \a itemModel and an optional \a parent.
417 * The proxy doesn't take ownership of the \a itemModel, as typically item models
418 * are owned by other controls. The role mappings are set with \a rowRole, \a
419 * columnRole, and \a valueRole.
420 */
421QItemModelBarDataProxy::QItemModelBarDataProxy(QAbstractItemModel *itemModel,
422 const QString &rowRole,
423 const QString &columnRole,
424 const QString &valueRole,
425 QObject *parent)
426 : QBarDataProxy(*(new QItemModelBarDataProxyPrivate(this)), parent)
427{
428 Q_D(QItemModelBarDataProxy);
429 d->m_itemModelHandler->setItemModel(itemModel);
430 d->m_rowRole = rowRole;
431 d->m_columnRole = columnRole;
432 d->m_valueRole = valueRole;
433 d->connectItemModelHandler();
434}
435
436/*!
437 * Constructs QItemModelBarDataProxy with \a itemModel and an optional \a parent.
438 * The proxy doesn't take ownership of the \a itemModel, as typically item models
439 * are owned by other controls. The role mappings are set with \a rowRole, \a
440 * columnRole, \a valueRole, and \a rotationRole.
441 */
442QItemModelBarDataProxy::QItemModelBarDataProxy(QAbstractItemModel *itemModel,
443 const QString &rowRole,
444 const QString &columnRole,
445 const QString &valueRole,
446 const QString &rotationRole,
447 QObject *parent)
448 : QBarDataProxy(*(new QItemModelBarDataProxyPrivate(this)), parent)
449{
450 Q_D(QItemModelBarDataProxy);
451 d->m_itemModelHandler->setItemModel(itemModel);
452 d->m_rowRole = rowRole;
453 d->m_columnRole = columnRole;
454 d->m_valueRole = valueRole;
455 d->m_rotationRole = rotationRole;
456 d->connectItemModelHandler();
457}
458
459/*!
460 * Constructs QItemModelBarDataProxy with \a itemModel and an optional \a parent.
461 * The proxy doesn't take ownership of the \a itemModel, as typically item models
462 * are owned by other controls. The role mappings are set with \a rowRole, \a
463 * columnRole, and \a valueRole. Row and column categories are set with \a
464 * rowCategories and \a columnCategories. This constructor also sets
465 * autoRowCategories and autoColumnCategories to false.
466 */
467QItemModelBarDataProxy::QItemModelBarDataProxy(QAbstractItemModel *itemModel,
468 const QString &rowRole,
469 const QString &columnRole,
470 const QString &valueRole,
471 const QStringList &rowCategories,
472 const QStringList &columnCategories,
473 QObject *parent)
474 : QBarDataProxy(*(new QItemModelBarDataProxyPrivate(this)), parent)
475{
476 Q_D(QItemModelBarDataProxy);
477 d->m_itemModelHandler->setItemModel(itemModel);
478 d->m_rowRole = rowRole;
479 d->m_columnRole = columnRole;
480 d->m_valueRole = valueRole;
481 d->m_rowCategories = rowCategories;
482 d->m_columnCategories = columnCategories;
483 d->m_autoRowCategories = false;
484 d->m_autoColumnCategories = false;
485 d->connectItemModelHandler();
486}
487
488/*!
489 * Constructs QItemModelBarDataProxy with \a itemModel and an optional \a parent.
490 * The proxy doesn't take ownership of the \a itemModel, as typically item models
491 * are owned by other controls. The role mappings are set with \a rowRole, \a
492 * columnRole, \a valueRole, and \a rotationRole. Row and column categories are
493 * set with \a rowCategories and \a columnCategories. This constructor also sets
494 * autoRowCategories and autoColumnCategories to false.
495 */
496QItemModelBarDataProxy::QItemModelBarDataProxy(QAbstractItemModel *itemModel,
497 const QString &rowRole,
498 const QString &columnRole,
499 const QString &valueRole,
500 const QString &rotationRole,
501 const QStringList &rowCategories,
502 const QStringList &columnCategories,
503 QObject *parent)
504 : QBarDataProxy(*(new QItemModelBarDataProxyPrivate(this)), parent)
505{
506 Q_D(QItemModelBarDataProxy);
507 d->m_itemModelHandler->setItemModel(itemModel);
508 d->m_rowRole = rowRole;
509 d->m_columnRole = columnRole;
510 d->m_valueRole = valueRole;
511 d->m_rotationRole = rotationRole;
512 d->m_rowCategories = rowCategories;
513 d->m_columnCategories = columnCategories;
514 d->m_autoRowCategories = false;
515 d->m_autoColumnCategories = false;
516 d->connectItemModelHandler();
517}
518
519/*!
520 * Destroys QItemModelBarDataProxy.
521 */
522QItemModelBarDataProxy::~QItemModelBarDataProxy() {}
523
524/*!
525 * \property QItemModelBarDataProxy::itemModel
526 *
527 * \brief The item model.
528 */
529
530/*!
531 * Sets the item model to \a itemModel. Does not take ownership of the model,
532 * but does connect to it to listen for changes.
533 */
534void QItemModelBarDataProxy::setItemModel(QAbstractItemModel *itemModel)
535{
536 Q_D(QItemModelBarDataProxy);
537 d->m_itemModelHandler->setItemModel(itemModel);
538}
539
540QAbstractItemModel *QItemModelBarDataProxy::itemModel() const
541{
542 Q_D(const QItemModelBarDataProxy);
543 return d->m_itemModelHandler->itemModel();
544}
545
546/*!
547 * \property QItemModelBarDataProxy::rowRole
548 *
549 * \brief The row role for the mapping.
550 */
551void QItemModelBarDataProxy::setRowRole(const QString &role)
552{
553 Q_D(QItemModelBarDataProxy);
554 if (d->m_rowRole == role) {
555 qCDebug(lcProperties3D, "%s Value is already set to: %s",
556 qUtf8Printable(QLatin1String(__FUNCTION__)), qUtf8Printable(role));
557 return;
558 }
559 d->m_rowRole = role;
560 emit rowRoleChanged(role);
561}
562
563QString QItemModelBarDataProxy::rowRole() const
564{
565 Q_D(const QItemModelBarDataProxy);
566 return d->m_rowRole;
567}
568
569/*!
570 * \property QItemModelBarDataProxy::columnRole
571 *
572 * \brief The column role for the mapping.
573 */
574void QItemModelBarDataProxy::setColumnRole(const QString &role)
575{
576 Q_D(QItemModelBarDataProxy);
577 if (d->m_columnRole == role) {
578 qCDebug(lcProperties3D, "%s value is already set to: %s",
579 qUtf8Printable(QLatin1String(__FUNCTION__)), qUtf8Printable(role));
580 return;
581 }
582 d->m_columnRole = role;
583 emit columnRoleChanged(role);
584}
585
586QString QItemModelBarDataProxy::columnRole() const
587{
588 Q_D(const QItemModelBarDataProxy);
589 return d->m_columnRole;
590}
591
592/*!
593 * \property QItemModelBarDataProxy::valueRole
594 *
595 * \brief The value role for the mapping.
596 */
597void QItemModelBarDataProxy::setValueRole(const QString &role)
598{
599 Q_D(QItemModelBarDataProxy);
600 if (d->m_valueRole == role) {
601 qCDebug(lcProperties3D, "%s Value is already set to: %s",
602 qUtf8Printable(QLatin1String(__FUNCTION__)), qUtf8Printable(role));
603 return;
604 }
605 d->m_valueRole = role;
606 emit valueRoleChanged(role);
607}
608
609QString QItemModelBarDataProxy::valueRole() const
610{
611 Q_D(const QItemModelBarDataProxy);
612 return d->m_valueRole;
613}
614
615/*!
616 * \property QItemModelBarDataProxy::rotationRole
617 *
618 * \brief The rotation role for the mapping.
619 */
620void QItemModelBarDataProxy::setRotationRole(const QString &role)
621{
622 Q_D(QItemModelBarDataProxy);
623 if (d->m_rotationRole == role) {
624 qCDebug(lcProperties3D, "%s value is already set to: %s",
625 qUtf8Printable(QLatin1String(__FUNCTION__)), qUtf8Printable(role));
626 return;
627 }
628 d->m_rotationRole = role;
629 emit rotationRoleChanged(role);
630}
631
632QString QItemModelBarDataProxy::rotationRole() const
633{
634 Q_D(const QItemModelBarDataProxy);
635 return d->m_rotationRole;
636}
637
638/*!
639 * \property QItemModelBarDataProxy::rowCategories
640 *
641 * \brief The row categories for the mapping.
642 */
643void QItemModelBarDataProxy::setRowCategories(const QStringList &categories)
644{
645 Q_D(QItemModelBarDataProxy);
646 if (d->m_rowCategories == categories) {
647 qCDebug(lcProperties3D) << qUtf8Printable(QLatin1String(__FUNCTION__))
648 << "value is already set to:" << categories;
649 return;
650 }
651 d->m_rowCategories = categories;
652 emit rowCategoriesChanged();
653}
654
655QStringList QItemModelBarDataProxy::rowCategories() const
656{
657 Q_D(const QItemModelBarDataProxy);
658 return d->m_rowCategories;
659}
660
661/*!
662 * \property QItemModelBarDataProxy::columnCategories
663 *
664 * \brief The column categories for the mapping.
665 */
666void QItemModelBarDataProxy::setColumnCategories(const QStringList &categories)
667{
668 Q_D(QItemModelBarDataProxy);
669 if (d->m_columnCategories == categories) {
670 qCDebug(lcProperties3D) << __FUNCTION__
671 << "value is already set to:" << categories;
672 return;
673 }
674 d->m_columnCategories = categories;
675 emit columnCategoriesChanged();
676}
677
678QStringList QItemModelBarDataProxy::columnCategories() const
679{
680 Q_D(const QItemModelBarDataProxy);
681 return d->m_columnCategories;
682}
683
684/*!
685 * \property QItemModelBarDataProxy::useModelCategories
686 *
687 * \brief Whether row and column roles and categories are used for mapping.
688 *
689 * When set to \c true, the mapping ignores row and column roles and categories,
690 * and uses the rows and columns from the model instead. Defaults to \c{false}.
691 */
692void QItemModelBarDataProxy::setUseModelCategories(bool enable)
693{
694 Q_D(QItemModelBarDataProxy);
695 if (d->m_useModelCategories == enable) {
696 qCDebug(lcProperties3D) << __FUNCTION__
697 << "value is already set to:" << enable;
698 return;
699 }
700 d->m_useModelCategories = enable;
701 emit useModelCategoriesChanged(enable);
702}
703
704bool QItemModelBarDataProxy::useModelCategories() const
705{
706 Q_D(const QItemModelBarDataProxy);
707 return d->m_useModelCategories;
708}
709
710/*!
711 * \property QItemModelBarDataProxy::autoRowCategories
712 *
713 * \brief Whether row categories are generated automatically.
714 *
715 * When set to \c true, the mapping ignores any explicitly set row categories
716 * and overwrites them with automatically generated ones whenever the
717 * data from model is resolved. Defaults to \c{true}.
718 */
719void QItemModelBarDataProxy::setAutoRowCategories(bool enable)
720{
721 Q_D(QItemModelBarDataProxy);
722 if (d->m_autoRowCategories == enable) {
723 qCDebug(lcProperties3D) << __FUNCTION__
724 << "value is already set to:" << enable;
725 return;
726 }
727 d->m_autoRowCategories = enable;
728 emit autoRowCategoriesChanged(enable);
729}
730
731bool QItemModelBarDataProxy::autoRowCategories() const
732{
733 Q_D(const QItemModelBarDataProxy);
734 return d->m_autoRowCategories;
735}
736
737/*!
738 * \property QItemModelBarDataProxy::autoColumnCategories
739 *
740 * \brief Whether column categories are generated automatically.
741 *
742 * When set to \c true, the mapping ignores any explicitly set column categories
743 * and overwrites them with automatically generated ones whenever the
744 * data from model is resolved. Defaults to \c{true}.
745 */
746void QItemModelBarDataProxy::setAutoColumnCategories(bool enable)
747{
748 Q_D(QItemModelBarDataProxy);
749 if (d->m_autoColumnCategories == enable) {
750 qCDebug(lcProperties3D) << __FUNCTION__
751 << "value is already set to:" << enable;
752 return;
753 }
754 d->m_autoColumnCategories = enable;
755 emit autoColumnCategoriesChanged(enable);
756}
757
758bool QItemModelBarDataProxy::autoColumnCategories() const
759{
760 Q_D(const QItemModelBarDataProxy);
761 return d->m_autoColumnCategories;
762}
763
764/*!
765 * Changes \a rowRole, \a columnRole, \a valueRole, \a rotationRole,
766 * \a rowCategories and \a columnCategories to the mapping.
767 */
768void QItemModelBarDataProxy::remap(const QString &rowRole,
769 const QString &columnRole,
770 const QString &valueRole,
771 const QString &rotationRole,
772 const QStringList &rowCategories,
773 const QStringList &columnCategories)
774{
775 setRowRole(rowRole);
776 setColumnRole(columnRole);
777 setValueRole(valueRole);
778 setRotationRole(rotationRole);
779 setRowCategories(rowCategories);
780 setColumnCategories(columnCategories);
781}
782
783/*!
784 * Returns the index of the specified \a category in row categories list.
785 * If the row categories list is empty, -1 is returned.
786 * \note If the automatic row categories generation is in use, this method will
787 * not return a valid index before the data in the model is resolved for the
788 * first time.
789 */
790qsizetype QItemModelBarDataProxy::rowCategoryIndex(const QString &category)
791{
792 Q_D(QItemModelBarDataProxy);
793 return d->m_rowCategories.indexOf(str: category);
794}
795
796/*!
797 * Returns the index of the specified \a category in column categories list.
798 * If the category is not found, -1 is returned.
799 * \note If the automatic column categories generation is in use, this method
800 * will not return a valid index before the data in the model is resolved for
801 * the first time.
802 */
803qsizetype QItemModelBarDataProxy::columnCategoryIndex(const QString &category)
804{
805 Q_D(QItemModelBarDataProxy);
806 return d->m_columnCategories.indexOf(str: category);
807}
808
809/*!
810 * \property QItemModelBarDataProxy::rowRolePattern
811 *
812 * \brief Whether a search and replace is performed on the value mapped by row
813 * role before it is used as a row category.
814 *
815 * This property specifies the regular expression to find the portion of the
816 * mapped value to replace and rowRoleReplace property contains the replacement
817 * string. This is useful for example in parsing row and column categories from
818 * a single timestamp field in the item model.
819 *
820 * \sa rowRole, rowRoleReplace
821 */
822void QItemModelBarDataProxy::setRowRolePattern(const QRegularExpression &pattern)
823{
824 Q_D(QItemModelBarDataProxy);
825 if (d->m_rowRolePattern == pattern) {
826 qCDebug(lcProperties3D) << __FUNCTION__
827 << "value is already set to:" << pattern;
828 return;
829 }
830 d->m_rowRolePattern = pattern;
831 emit rowRolePatternChanged(pattern);
832}
833
834QRegularExpression QItemModelBarDataProxy::rowRolePattern() const
835{
836 Q_D(const QItemModelBarDataProxy);
837 return d->m_rowRolePattern;
838}
839
840/*!
841 * \property QItemModelBarDataProxy::columnRolePattern
842 *
843 * \brief Whether a search and replace is done on the value mapped by column
844 * role before it is used as a column category.
845 *
846 * This property specifies the regular expression to find the portion of the
847 * mapped value to replace and columnRoleReplace property contains the
848 * replacement string. This is useful for example in parsing row and column
849 * categories from a single timestamp field in the item model.
850 *
851 * \sa columnRole, columnRoleReplace
852 */
853void QItemModelBarDataProxy::setColumnRolePattern(const QRegularExpression &pattern)
854{
855 Q_D(QItemModelBarDataProxy);
856 if (d->m_columnRolePattern == pattern) {
857 qCDebug(lcProperties3D) << __FUNCTION__
858 << "value is already set to:" << pattern;
859 return;
860 }
861 d->m_columnRolePattern = pattern;
862 emit columnRolePatternChanged(pattern);
863}
864
865QRegularExpression QItemModelBarDataProxy::columnRolePattern() const
866{
867 Q_D(const QItemModelBarDataProxy);
868 return d->m_columnRolePattern;
869}
870
871/*!
872 * \property QItemModelBarDataProxy::valueRolePattern
873 *
874 * \brief Whether a search and replace is done on the value mapped by value role
875 * before it is used as a bar value.
876 *
877 * This property specifies the regular expression to find the portion of the
878 * mapped value to replace and valueRoleReplace property contains the
879 * replacement string.
880 *
881 * \sa valueRole, valueRoleReplace
882 */
883void QItemModelBarDataProxy::setValueRolePattern(const QRegularExpression &pattern)
884{
885 Q_D(QItemModelBarDataProxy);
886 if (d->m_valueRolePattern == pattern) {
887 qCDebug(lcProperties3D) << __FUNCTION__
888 << "value is already set to:" << pattern;
889 return;
890 }
891 d->m_valueRolePattern = pattern;
892 emit valueRolePatternChanged(pattern);
893}
894
895QRegularExpression QItemModelBarDataProxy::valueRolePattern() const
896{
897 Q_D(const QItemModelBarDataProxy);
898 return d->m_valueRolePattern;
899}
900
901/*!
902 * \property QItemModelBarDataProxy::rotationRolePattern
903 *
904 * \brief Whether a search and replace is done on the value mapped by rotation
905 * role before it is used as a bar rotation angle.
906 *
907 * This property specifies the regular expression to find the portion
908 * of the mapped value to replace and rotationRoleReplace property contains the
909 * replacement string.
910 *
911 * \sa rotationRole, rotationRoleReplace
912 */
913void QItemModelBarDataProxy::setRotationRolePattern(const QRegularExpression &pattern)
914{
915 Q_D(QItemModelBarDataProxy);
916 if (d->m_rotationRolePattern == pattern) {
917 qCDebug(lcProperties3D) << __FUNCTION__
918 << "value is already set to:" << pattern;
919 return;
920 }
921 d->m_rotationRolePattern = pattern;
922 emit rotationRolePatternChanged(pattern);
923}
924
925QRegularExpression QItemModelBarDataProxy::rotationRolePattern() const
926{
927 Q_D(const QItemModelBarDataProxy);
928 return d->m_rotationRolePattern;
929}
930
931/*!
932 * \property QItemModelBarDataProxy::rowRoleReplace
933 *
934 * \brief The replacement content to be used in conjunction with rowRolePattern.
935 *
936 * Defaults to empty string. For more information on how the search and replace
937 * using regular expressions works, see QString::replace(const
938 * QRegularExpression &rx, const QString &after) function documentation.
939 *
940 * \sa rowRole, rowRolePattern
941 */
942void QItemModelBarDataProxy::setRowRoleReplace(const QString &replace)
943{
944 Q_D(QItemModelBarDataProxy);
945 if (d->m_rowRoleReplace == replace) {
946 qCDebug(lcProperties3D, "%s value is already set to: %s",
947 qUtf8Printable(QLatin1String(__FUNCTION__)), qUtf8Printable(replace));
948 return;
949 }
950 d->m_rowRoleReplace = replace;
951 emit rowRoleReplaceChanged(replace);
952}
953
954QString QItemModelBarDataProxy::rowRoleReplace() const
955{
956 Q_D(const QItemModelBarDataProxy);
957 return d->m_rowRoleReplace;
958}
959
960/*!
961 * \property QItemModelBarDataProxy::columnRoleReplace
962 *
963 * \brief The replacement content to be used in conjunction with columnRolePattern.
964 *
965 * Defaults to empty string. For more information on how the search and replace
966 * using regular expressions works, see QString::replace(const
967 * QRegularExpression &rx, const QString &after) function documentation.
968 *
969 * \sa columnRole, columnRolePattern
970 */
971void QItemModelBarDataProxy::setColumnRoleReplace(const QString &replace)
972{
973 Q_D(QItemModelBarDataProxy);
974 if (d->m_columnRoleReplace == replace) {
975 qCDebug(lcProperties3D, "%s value is already set to: %s",
976 qUtf8Printable(QLatin1String(__FUNCTION__)), qUtf8Printable(replace));
977 return;
978 }
979 d->m_columnRoleReplace = replace;
980 emit columnRoleReplaceChanged(replace);
981}
982
983QString QItemModelBarDataProxy::columnRoleReplace() const
984{
985 Q_D(const QItemModelBarDataProxy);
986 return d->m_columnRoleReplace;
987}
988
989/*!
990 * \property QItemModelBarDataProxy::valueRoleReplace
991 *
992 * \brief The replacement content to be used in conjunction with valueRolePattern.
993 *
994 * Defaults to empty string. For more information on how the search and replace
995 * using regular expressions works, see QString::replace(const
996 * QRegularExpression &rx, const QString &after) function documentation.
997 *
998 * \sa valueRole, valueRolePattern
999 */
1000void QItemModelBarDataProxy::setValueRoleReplace(const QString &replace)
1001{
1002 Q_D(QItemModelBarDataProxy);
1003 if (d->m_valueRoleReplace == replace) {
1004 qCDebug(lcProperties3D, "%s value is already set to: %s",
1005 qUtf8Printable(QLatin1String(__FUNCTION__)), qUtf8Printable(replace));
1006 return;
1007 }
1008 d->m_valueRoleReplace = replace;
1009 emit valueRoleReplaceChanged(replace);
1010}
1011
1012QString QItemModelBarDataProxy::valueRoleReplace() const
1013{
1014 Q_D(const QItemModelBarDataProxy);
1015 return d->m_valueRoleReplace;
1016}
1017
1018/*!
1019 * \property QItemModelBarDataProxy::rotationRoleReplace
1020 *
1021 * \brief The replacement content to be used in conjunction with
1022 * rotationRolePattern.
1023 *
1024 * Defaults to empty string. For more information on how the search and replace
1025 * using regular expressions works, see QString::replace(const
1026 * QRegularExpression &rx, const QString &after) function documentation.
1027 *
1028 * \sa rotationRole, rotationRolePattern
1029 */
1030void QItemModelBarDataProxy::setRotationRoleReplace(const QString &replace)
1031{
1032 Q_D(QItemModelBarDataProxy);
1033 if (d->m_rotationRoleReplace == replace) {
1034 qCDebug(lcProperties3D, "%s value is already set to: %s",
1035 qUtf8Printable(QLatin1String(__FUNCTION__)), qUtf8Printable(replace));
1036 return;
1037 }
1038 d->m_rotationRoleReplace = replace;
1039 emit rotationRoleReplaceChanged(replace);
1040}
1041
1042QString QItemModelBarDataProxy::rotationRoleReplace() const
1043{
1044 Q_D(const QItemModelBarDataProxy);
1045 return d->m_rotationRoleReplace;
1046}
1047
1048/*!
1049 * \property QItemModelBarDataProxy::multiMatchBehavior
1050 *
1051 * \brief How multiple matches for each row/column combination are handled.
1052 *
1053 * Defaults to QItemModelBarDataProxy::MultiMatchBehavior::Last. The chosen
1054 * behavior affects both bar value and rotation.
1055 *
1056 * For example, you might have an item model with timestamped data taken at
1057 * irregular intervals and you want to visualize total value of data items on
1058 * each day with a bar graph. This can be done by specifying row and column
1059 * categories so that each bar represents a day, and setting multiMatchBehavior
1060 * to QItemModelBarDataProxy::MultiMatchBehavior::Cumulative.
1061 */
1062void QItemModelBarDataProxy::setMultiMatchBehavior(
1063 QItemModelBarDataProxy::MultiMatchBehavior behavior)
1064{
1065 Q_D(QItemModelBarDataProxy);
1066 if (d->m_multiMatchBehavior == behavior) {
1067 qCDebug(lcProperties3D) << __FUNCTION__
1068 << "value is already set to:" << behavior;
1069 return;
1070 }
1071 d->m_multiMatchBehavior = behavior;
1072 emit multiMatchBehaviorChanged(behavior);
1073}
1074
1075QItemModelBarDataProxy::MultiMatchBehavior QItemModelBarDataProxy::multiMatchBehavior() const
1076{
1077 Q_D(const QItemModelBarDataProxy);
1078 return d->m_multiMatchBehavior;
1079}
1080
1081// QItemModelBarDataProxyPrivate
1082
1083QItemModelBarDataProxyPrivate::QItemModelBarDataProxyPrivate(QItemModelBarDataProxy *q)
1084 : m_itemModelHandler(new BarItemModelHandler(q))
1085 , m_useModelCategories(false)
1086 , m_autoRowCategories(true)
1087 , m_autoColumnCategories(true)
1088 , m_multiMatchBehavior(QItemModelBarDataProxy::MultiMatchBehavior::Last)
1089{}
1090
1091QItemModelBarDataProxyPrivate::~QItemModelBarDataProxyPrivate()
1092{
1093 delete m_itemModelHandler;
1094}
1095
1096void QItemModelBarDataProxyPrivate::connectItemModelHandler()
1097{
1098 Q_Q(QItemModelBarDataProxy);
1099 QObject::connect(sender: m_itemModelHandler,
1100 signal: &BarItemModelHandler::itemModelChanged,
1101 context: q,
1102 slot: &QItemModelBarDataProxy::itemModelChanged);
1103 QObject::connect(sender: q,
1104 signal: &QItemModelBarDataProxy::rowRoleChanged,
1105 context: m_itemModelHandler,
1106 slot: &AbstractItemModelHandler::handleMappingChanged);
1107 QObject::connect(sender: q,
1108 signal: &QItemModelBarDataProxy::columnRoleChanged,
1109 context: m_itemModelHandler,
1110 slot: &AbstractItemModelHandler::handleMappingChanged);
1111 QObject::connect(sender: q,
1112 signal: &QItemModelBarDataProxy::valueRoleChanged,
1113 context: m_itemModelHandler,
1114 slot: &AbstractItemModelHandler::handleMappingChanged);
1115 QObject::connect(sender: q,
1116 signal: &QItemModelBarDataProxy::rotationRoleChanged,
1117 context: m_itemModelHandler,
1118 slot: &AbstractItemModelHandler::handleMappingChanged);
1119 QObject::connect(sender: q,
1120 signal: &QItemModelBarDataProxy::rowCategoriesChanged,
1121 context: m_itemModelHandler,
1122 slot: &AbstractItemModelHandler::handleMappingChanged);
1123 QObject::connect(sender: q,
1124 signal: &QItemModelBarDataProxy::columnCategoriesChanged,
1125 context: m_itemModelHandler,
1126 slot: &AbstractItemModelHandler::handleMappingChanged);
1127 QObject::connect(sender: q,
1128 signal: &QItemModelBarDataProxy::useModelCategoriesChanged,
1129 context: m_itemModelHandler,
1130 slot: &AbstractItemModelHandler::handleMappingChanged);
1131 QObject::connect(sender: q,
1132 signal: &QItemModelBarDataProxy::autoRowCategoriesChanged,
1133 context: m_itemModelHandler,
1134 slot: &AbstractItemModelHandler::handleMappingChanged);
1135 QObject::connect(sender: q,
1136 signal: &QItemModelBarDataProxy::autoColumnCategoriesChanged,
1137 context: m_itemModelHandler,
1138 slot: &AbstractItemModelHandler::handleMappingChanged);
1139 QObject::connect(sender: q,
1140 signal: &QItemModelBarDataProxy::rowRolePatternChanged,
1141 context: m_itemModelHandler,
1142 slot: &AbstractItemModelHandler::handleMappingChanged);
1143 QObject::connect(sender: q,
1144 signal: &QItemModelBarDataProxy::columnRolePatternChanged,
1145 context: m_itemModelHandler,
1146 slot: &AbstractItemModelHandler::handleMappingChanged);
1147 QObject::connect(sender: q,
1148 signal: &QItemModelBarDataProxy::valueRolePatternChanged,
1149 context: m_itemModelHandler,
1150 slot: &AbstractItemModelHandler::handleMappingChanged);
1151 QObject::connect(sender: q,
1152 signal: &QItemModelBarDataProxy::rotationRolePatternChanged,
1153 context: m_itemModelHandler,
1154 slot: &AbstractItemModelHandler::handleMappingChanged);
1155 QObject::connect(sender: q,
1156 signal: &QItemModelBarDataProxy::rowRoleReplaceChanged,
1157 context: m_itemModelHandler,
1158 slot: &AbstractItemModelHandler::handleMappingChanged);
1159 QObject::connect(sender: q,
1160 signal: &QItemModelBarDataProxy::columnRoleReplaceChanged,
1161 context: m_itemModelHandler,
1162 slot: &AbstractItemModelHandler::handleMappingChanged);
1163 QObject::connect(sender: q,
1164 signal: &QItemModelBarDataProxy::valueRoleReplaceChanged,
1165 context: m_itemModelHandler,
1166 slot: &AbstractItemModelHandler::handleMappingChanged);
1167 QObject::connect(sender: q,
1168 signal: &QItemModelBarDataProxy::rotationRoleReplaceChanged,
1169 context: m_itemModelHandler,
1170 slot: &AbstractItemModelHandler::handleMappingChanged);
1171 QObject::connect(sender: q,
1172 signal: &QItemModelBarDataProxy::multiMatchBehaviorChanged,
1173 context: m_itemModelHandler,
1174 slot: &AbstractItemModelHandler::handleMappingChanged);
1175}
1176
1177QT_END_NAMESPACE
1178

source code of qtgraphs/src/graphs3d/data/qitemmodelbardataproxy.cpp