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

source code of qtgraphs/src/graphs/data/qitemmodelsurfacedataproxy.cpp