// Copyright (C) 2016 The Qt Company Ltd.
// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only

#include "qitemmodelbardataproxy_p.h"
#include "baritemmodelhandler_p.h"

QT_BEGIN_NAMESPACE

/*!
 * \class QItemModelBarDataProxy
 * \inmodule QtDataVisualization
 * \brief Proxy class for presenting data in item models with Q3DBars.
 * \since QtDataVisualization 1.0
 *
 * QItemModelBarDataProxy allows you to use QAbstractItemModel derived models as a data source
 * for Q3DBars. It uses the defined mappings to map data from the model to rows, columns, and
 * values of Q3DBars graph.
 *
 * The data is resolved asynchronously whenever mappings or the model changes.
 * QBarDataProxy::arrayReset() is emitted when the data has been resolved.
 * However, when useModelCategories property is set to true, single item changes are resolved
 * synchronously, unless the same frame also contains a change that causes the whole model to be
 * resolved.
 *
 * Mappings can be used in the following ways:
 *
 * \list
 * \li If useModelCategories property is set to true, this proxy will map rows and
 *    columns of QAbstractItemModel directly to rows and columns of Q3DBars, and uses the value
 *    returned for Qt::DisplayRole as bar value by default.
 *    The value role to be used can be redefined if Qt::DisplayRole is not suitable.
 *
 * \li For models that do not have data already neatly sorted into rows and columns, such as
 *    QAbstractListModel based models, you can define a role from the model to map for each of row,
 *    column and value.
 *
 * \li If you do not want to include all data contained in the model, or the autogenerated rows and
 *    columns are not ordered as you wish, you can specify which rows and columns should be included
 *    and in which order by defining an explicit list of categories for either or both of rows and
 *    columns.
 * \endlist
 *
 * For example, assume that you have a custom QAbstractItemModel for storing various monthly values
 * related to a business.
 * Each item in the model has the roles "year", "month", "income", and "expenses".
 * You could do the following to display the data in a bar graph:
 *
 * \snippet doc_src_qtdatavisualization.cpp 3
 *
 * If the fields of the model do not contain the data in the exact format you need, you can specify
 * a search pattern regular expression and a replace rule for each role to get the value in a
 * format you need. For more information how the replace using regular expressions works, see
 * QString::replace(const QRegularExpression &rx, const QString &after) function documentation. Note that
 * using regular expressions has an impact on the performance, so it's more efficient to utilize
 * item models where doing search and replace is not necessary to get the desired values.
 *
 * For example about using the search patterns in conjunction with the roles, see
 * \l{Simple Bar Graph} example.
 *
 * \sa {Qt Data Visualization Data Handling}
 */

/*!
 * \qmltype ItemModelBarDataProxy
 * \inqmlmodule QtDataVisualization
 * \since QtDataVisualization 1.0
 * \ingroup datavisualization_qml
 * \nativetype QItemModelBarDataProxy
 * \inherits BarDataProxy
 * \brief Proxy class for presenting data in item models with Bars3D.
 *
 * This type allows you to use AbstractItemModel derived models as a data source for Bars3D.
 *
 * Data is resolved asynchronously whenever the mapping or the model changes.
 * QBarDataProxy::arrayReset() is emitted when the data has been resolved.
 *
 * For ItemModelBarDataProxy enums, see \l{QItemModelBarDataProxy::MultiMatchBehavior}.
 *
 * For more details, see QItemModelBarDataProxy documentation.
 *
 * Usage example:
 *
 * \snippet doc_src_qmldatavisualization.cpp 7
 *
 * \sa BarDataProxy, {Qt Data Visualization Data Handling}
 */

/*!
 * \qmlproperty model ItemModelBarDataProxy::itemModel
 * The item model.
 */

/*!
 * \qmlproperty string ItemModelBarDataProxy::rowRole
 * The item model role to map into row category.
 */

/*!
 * \qmlproperty string ItemModelBarDataProxy::columnRole
 * The item model role to map into column category.
 */

/*!
 * \qmlproperty string ItemModelBarDataProxy::valueRole
 * The item model role to map into bar value.
 */

/*!
 * \qmlproperty string ItemModelBarDataProxy::rotationRole
 * The item model role to map into bar rotation angle.
 */

/*!
 * \qmlproperty list<String> ItemModelBarDataProxy::rowCategories
 * The row categories of the mapping. Only items with row role values that are found in this list
 * are included when the data is resolved. The rows are ordered in the same order as they are in
 * this list.
 */

/*!
 * \qmlproperty list<String> ItemModelBarDataProxy::columnCategories
 * The column categories of the mapping. Only items with column role values that are found in this
 * list are included when the data is resolved. The columns are ordered in the same order as they
 * are in this list.
 */

/*!
 * \qmlproperty bool ItemModelBarDataProxy::useModelCategories
 * When set to \c true, the mapping ignores row and column roles and categories, and uses
 * the rows and columns from the model instead. Row and column headers are used for row and column
 * labels. Defaults to \c{false}.
 */

/*!
 * \qmlproperty bool ItemModelBarDataProxy::autoRowCategories
 * When set to \c true, the mapping ignores any explicitly set row categories
 * and overwrites them with automatically generated ones whenever the
 * data from the model is resolved. Defaults to \c{true}.
 */

/*!
 * \qmlproperty bool ItemModelBarDataProxy::autoColumnCategories
 * When set to \c true, the mapping ignores any explicitly set column categories
 * and overwrites them with automatically generated ones whenever the
 * data from model is resolved. Defaults to \c{true}.
 */

/*!
 * \qmlproperty regExp ItemModelBarDataProxy::rowRolePattern
 * When set, a search and replace is done on the value mapped by row role before it is used as
 * a row category. This property specifies the regular expression to find the portion of the
 * mapped value to replace and rowRoleReplace property contains the replacement string.
 * This is useful for example in parsing row and column categories from a single
 * timestamp field in the item model.
 *
 * \sa rowRole, rowRoleReplace
 */

/*!
 * \qmlproperty regExp ItemModelBarDataProxy::columnRolePattern
 * When set, a search and replace is done on the value mapped by column role before it is used
 * as a column category. This property specifies the regular expression to find the portion of the
 * mapped value to replace and columnRoleReplace property contains the replacement string.
 * This is useful for example in parsing row and column categories from
 * a single timestamp field in the item model.
 *
 * \sa columnRole, columnRoleReplace
 */

/*!
 * \qmlproperty regExp ItemModelBarDataProxy::valueRolePattern
 * When set, a search and replace is done on the value mapped by value role before it is used as
 * a bar value. This property specifies the regular expression to find the portion of the
 * mapped value to replace and valueRoleReplace property contains the replacement string.
 *
 * \sa valueRole, valueRoleReplace
 */

/*!
 * \qmlproperty regExp ItemModelBarDataProxy::rotationRolePattern
 * When set, a search and replace is done on the value mapped by rotation role before it is used
 * as a bar rotation angle. This property specifies the regular expression to find the portion
 * of the mapped value to replace and rotationRoleReplace property contains the replacement string.
 *
 * \sa rotationRole, rotationRoleReplace
 */

/*!
 * \qmlproperty string ItemModelBarDataProxy::rowRoleReplace
 * This property defines the replace content to be used in conjunction with rowRolePattern.
 * Defaults to empty string. For more information on how the search and replace using regular
 * expressions works, see QString::replace(const QRegularExpression &rx, const QString &after)
 * function documentation.
 *
 * \sa rowRole, rowRolePattern
 */

/*!
 * \qmlproperty string ItemModelBarDataProxy::columnRoleReplace
 * This property defines the replace content to be used in conjunction with columnRolePattern.
 * Defaults to empty string. For more information on how the search and replace using regular
 * expressions works, see QString::replace(const QRegularExpression &rx, const QString &after)
 * function documentation.
 *
 * \sa columnRole, columnRolePattern
 */

/*!
 * \qmlproperty string ItemModelBarDataProxy::valueRoleReplace
 * This property defines the replace content to be used in conjunction with valueRolePattern.
 * Defaults to empty string. For more information on how the search and replace using regular
 * expressions works, see QString::replace(const QRegularExpression &rx, const QString &after)
 * function documentation.
 *
 * \sa valueRole, valueRolePattern
 */

/*!
 * \qmlproperty string ItemModelBarDataProxy::rotationRoleReplace
 * This property defines the replace content to be used in conjunction with rotationRolePattern.
 * Defaults to empty string. For more information on how the search and replace using regular
 * expressions works, see QString::replace(const QRegularExpression &rx, const QString &after)
 * function documentation.
 *
 * \sa rotationRole, rotationRolePattern
 */

/*!
 * \qmlproperty ItemModelBarDataProxy.MultiMatchBehavior ItemModelBarDataProxy::multiMatchBehavior
 * Defines how multiple matches for each row/column combination are handled.
 * Defaults to \l{QItemModelBarDataProxy::MMBLast}{ItemModelBarDataProxy.MMBLast}. The chosen
 * behavior affects both bar value and rotation.
 *
 * For example, you might have an item model with timestamped data taken at irregular intervals
 * and you want to visualize total value of data items on each day with a bar graph.
 * This can be done by specifying row and column categories so that each bar represents a day,
 * and setting multiMatchBehavior to
 * \l{QItemModelBarDataProxy::MMBCumulative}{ItemModelBarDataProxy.MMBCumulative}.
 */

/*!
 *  \enum QItemModelBarDataProxy::MultiMatchBehavior
 *
 *  Behavior types for QItemModelBarDataProxy::multiMatchBehavior property.
 *
 *  \value MMBFirst
 *         The value is taken from the first item in the item model that matches
 *         each row/column combination.
 *  \value MMBLast
 *         The value is taken from the last item in the item model that matches
 *         each row/column combination.
 *  \value MMBAverage
 *         The values from all items matching each row/column combination are
 *         averaged together and the average is used as the bar value.
 *  \value MMBCumulative
 *         The values from all items matching each row/column combination are
 *         added together and the total is used as the bar value.
 */

/*!
 * Constructs QItemModelBarDataProxy with optional \a parent.
 */
QItemModelBarDataProxy::QItemModelBarDataProxy(QObject *parent)
    : QBarDataProxy(new QItemModelBarDataProxyPrivate(this), parent)
{
    dptr()->connectItemModelHandler();
}

/*!
 * Constructs QItemModelBarDataProxy with \a itemModel and optional \a parent. Proxy doesn't take
 * ownership of the \a itemModel, as typically item models are owned by other controls.
 */
QItemModelBarDataProxy::QItemModelBarDataProxy(QAbstractItemModel *itemModel, QObject *parent)
    : QBarDataProxy(new QItemModelBarDataProxyPrivate(this), parent)
{
    setItemModel(itemModel);
    dptr()->connectItemModelHandler();
}

/*!
 * Constructs QItemModelBarDataProxy with \a itemModel and optional \a parent. Proxy doesn't take
 * ownership of the \a itemModel, as typically item models are owned by other controls.
 * The value role is set to \a valueRole.
 * This constructor is meant to be used with models that have data properly sorted
 * in rows and columns already, so it also sets useModelCategories property to true.
 */
QItemModelBarDataProxy::QItemModelBarDataProxy(QAbstractItemModel *itemModel,
                                               const QString &valueRole, QObject *parent)
    : QBarDataProxy(new QItemModelBarDataProxyPrivate(this), parent)
{
    dptr()->m_itemModelHandler->setItemModel(itemModel);
    dptr()->m_valueRole = valueRole;
    dptr()->m_useModelCategories = true;
    dptr()->connectItemModelHandler();
}

/*!
 * Constructs QItemModelBarDataProxy with \a itemModel and optional \a parent. Proxy doesn't take
 * ownership of the \a itemModel, as typically item models are owned by other controls.
 * The role mappings are set with \a rowRole, \a columnRole, and \a valueRole.
 */
QItemModelBarDataProxy::QItemModelBarDataProxy(QAbstractItemModel *itemModel,
                                               const QString &rowRole,
                                               const QString &columnRole,
                                               const QString &valueRole, QObject *parent)
    : QBarDataProxy(new QItemModelBarDataProxyPrivate(this), parent)
{
    dptr()->m_itemModelHandler->setItemModel(itemModel);
    dptr()->m_rowRole = rowRole;
    dptr()->m_columnRole = columnRole;
    dptr()->m_valueRole = valueRole;
    dptr()->connectItemModelHandler();
}

/*!
 * Constructs QItemModelBarDataProxy with \a itemModel and optional \a parent. Proxy doesn't take
 * ownership of the \a itemModel, as typically item models are owned by other controls.
 * The role mappings are set with \a rowRole, \a columnRole, \a valueRole, and \a rotationRole.
 */
QItemModelBarDataProxy::QItemModelBarDataProxy(QAbstractItemModel *itemModel,
                                               const QString &rowRole,
                                               const QString &columnRole,
                                               const QString &valueRole,
                                               const QString &rotationRole,
                                               QObject *parent)
    : QBarDataProxy(new QItemModelBarDataProxyPrivate(this), parent)
{
    dptr()->m_itemModelHandler->setItemModel(itemModel);
    dptr()->m_rowRole = rowRole;
    dptr()->m_columnRole = columnRole;
    dptr()->m_valueRole = valueRole;
    dptr()->m_rotationRole = rotationRole;
    dptr()->connectItemModelHandler();
}

/*!
 * Constructs QItemModelBarDataProxy with \a itemModel and optional \a parent. Proxy doesn't take
 * ownership of the \a itemModel, as typically item models are owned by other controls.
 * The role mappings are set with \a rowRole, \a columnRole, and \a valueRole.
 * Row and column categories are set with \a rowCategories and \a columnCategories.
 * This constructor also sets autoRowCategories and autoColumnCategories to false.
 */
QItemModelBarDataProxy::QItemModelBarDataProxy(QAbstractItemModel *itemModel,
                                               const QString &rowRole,
                                               const QString &columnRole,
                                               const QString &valueRole,
                                               const QStringList &rowCategories,
                                               const QStringList &columnCategories,
                                               QObject *parent)
    : QBarDataProxy(new QItemModelBarDataProxyPrivate(this), parent)
{
    dptr()->m_itemModelHandler->setItemModel(itemModel);
    dptr()->m_rowRole = rowRole;
    dptr()->m_columnRole = columnRole;
    dptr()->m_valueRole = valueRole;
    dptr()->m_rowCategories = rowCategories;
    dptr()->m_columnCategories = columnCategories;
    dptr()->m_autoRowCategories = false;
    dptr()->m_autoColumnCategories = false;
    dptr()->connectItemModelHandler();
}

/*!
 * Constructs QItemModelBarDataProxy with \a itemModel and optional \a parent. Proxy doesn't take
 * ownership of the \a itemModel, as typically item models are owned by other controls.
 * The role mappings are set with \a rowRole, \a columnRole, \a valueRole, and \a rotationRole.
 * Row and column categories are set with \a rowCategories and \a columnCategories.
 * This constructor also sets autoRowCategories and autoColumnCategories to false.
 */
QItemModelBarDataProxy::QItemModelBarDataProxy(QAbstractItemModel *itemModel,
                                               const QString &rowRole,
                                               const QString &columnRole,
                                               const QString &valueRole,
                                               const QString &rotationRole,
                                               const QStringList &rowCategories,
                                               const QStringList &columnCategories,
                                               QObject *parent)
    : QBarDataProxy(new QItemModelBarDataProxyPrivate(this), parent)
{
    dptr()->m_itemModelHandler->setItemModel(itemModel);
    dptr()->m_rowRole = rowRole;
    dptr()->m_columnRole = columnRole;
    dptr()->m_valueRole = valueRole;
    dptr()->m_rotationRole = rotationRole;
    dptr()->m_rowCategories = rowCategories;
    dptr()->m_columnCategories = columnCategories;
    dptr()->m_autoRowCategories = false;
    dptr()->m_autoColumnCategories = false;
    dptr()->connectItemModelHandler();
}

/*!
 * Destroys QItemModelBarDataProxy.
 */
QItemModelBarDataProxy::~QItemModelBarDataProxy()
{
}

/*!
 * \property QItemModelBarDataProxy::itemModel
 *
 * \brief The item model.
 */

/*!
 * Sets the item model to \a itemModel. Does not take ownership of the model,
 * but does connect to it to listen for changes.
 */
void QItemModelBarDataProxy::setItemModel(QAbstractItemModel *itemModel)
{
    dptr()->m_itemModelHandler->setItemModel(itemModel);
}

QAbstractItemModel *QItemModelBarDataProxy::itemModel() const
{
    return dptrc()->m_itemModelHandler->itemModel();
}

/*!
 * \property QItemModelBarDataProxy::rowRole
 *
 * \brief The row role for the mapping.
 */
void QItemModelBarDataProxy::setRowRole(const QString &role)
{
    if (dptr()->m_rowRole != role) {
        dptr()->m_rowRole = role;
        emit rowRoleChanged(role);
    }
}

QString QItemModelBarDataProxy::rowRole() const
{
    return dptrc()->m_rowRole;
}

/*!
 * \property QItemModelBarDataProxy::columnRole
 *
 * \brief The column role for the mapping.
 */
void QItemModelBarDataProxy::setColumnRole(const QString &role)
{
    if (dptr()->m_columnRole != role) {
        dptr()->m_columnRole = role;
        emit columnRoleChanged(role);
    }
}

QString QItemModelBarDataProxy::columnRole() const
{
    return dptrc()->m_columnRole;
}

/*!
 * \property QItemModelBarDataProxy::valueRole
 *
 * \brief The value role for the mapping.
 */
void QItemModelBarDataProxy::setValueRole(const QString &role)
{
    if (dptr()->m_valueRole != role) {
        dptr()->m_valueRole = role;
        emit valueRoleChanged(role);
    }
}

QString QItemModelBarDataProxy::valueRole() const
{
    return dptrc()->m_valueRole;
}

/*!
 * \property QItemModelBarDataProxy::rotationRole
 *
 * \brief The rotation role for the mapping.
 */
void QItemModelBarDataProxy::setRotationRole(const QString &role)
{
    if (dptr()->m_rotationRole != role) {
        dptr()->m_rotationRole = role;
        emit rotationRoleChanged(role);
    }
}

QString QItemModelBarDataProxy::rotationRole() const
{
    return dptrc()->m_rotationRole;
}

/*!
 * \property QItemModelBarDataProxy::rowCategories
 *
 * \brief The row categories for the mapping.
 */
void QItemModelBarDataProxy::setRowCategories(const QStringList &categories)
{
    if (dptr()->m_rowCategories != categories) {
        dptr()->m_rowCategories = categories;
        emit rowCategoriesChanged();
    }
}

QStringList QItemModelBarDataProxy::rowCategories() const
{
    return dptrc()->m_rowCategories;
}

/*!
 * \property QItemModelBarDataProxy::columnCategories
 *
 * \brief The column categories for the mapping.
 */
void QItemModelBarDataProxy::setColumnCategories(const QStringList &categories)
{
    if (dptr()->m_columnCategories != categories) {
        dptr()->m_columnCategories = categories;
        emit columnCategoriesChanged();
    }
}

QStringList QItemModelBarDataProxy::columnCategories() const
{
    return dptrc()->m_columnCategories;
}

/*!
 * \property QItemModelBarDataProxy::useModelCategories
 *
 * \brief Whether row and column roles and categories are used for mapping.
 *
 * When set to \c true, the mapping ignores row and column roles and categories, and uses
 * the rows and columns from the model instead. Defaults to \c{false}.
 */
void QItemModelBarDataProxy::setUseModelCategories(bool enable)
{
    if (dptr()->m_useModelCategories != enable) {
        dptr()->m_useModelCategories = enable;
        emit useModelCategoriesChanged(enable);
    }
}

bool QItemModelBarDataProxy::useModelCategories() const
{
    return dptrc()->m_useModelCategories;
}

/*!
 * \property QItemModelBarDataProxy::autoRowCategories
 *
 * \brief Whether row categories are generated automatically.
 *
 * When set to \c true, the mapping ignores any explicitly set row categories
 * and overwrites them with automatically generated ones whenever the
 * data from model is resolved. Defaults to \c{true}.
 */
void QItemModelBarDataProxy::setAutoRowCategories(bool enable)
{
    if (dptr()->m_autoRowCategories != enable) {
        dptr()->m_autoRowCategories = enable;
        emit autoRowCategoriesChanged(enable);
    }
}

bool QItemModelBarDataProxy::autoRowCategories() const
{
    return dptrc()->m_autoRowCategories;
}

/*!
 * \property QItemModelBarDataProxy::autoColumnCategories
 *
 * \brief Whether column categories are generated automatically.
 *
 * When set to \c true, the mapping ignores any explicitly set column categories
 * and overwrites them with automatically generated ones whenever the
 * data from model is resolved. Defaults to \c{true}.
 */
void QItemModelBarDataProxy::setAutoColumnCategories(bool enable)
{
    if (dptr()->m_autoColumnCategories != enable) {
        dptr()->m_autoColumnCategories = enable;
        emit autoColumnCategoriesChanged(enable);
    }
}

bool QItemModelBarDataProxy::autoColumnCategories() const
{
    return dptrc()->m_autoColumnCategories;
}

/*!
 * Changes \a rowRole, \a columnRole, \a valueRole, \a rotationRole,
 * \a rowCategories and \a columnCategories to the mapping.
 */
void QItemModelBarDataProxy::remap(const QString &rowRole,
                                   const QString &columnRole,
                                   const QString &valueRole,
                                   const QString &rotationRole,
                                   const QStringList &rowCategories,
                                   const QStringList &columnCategories)
{
    setRowRole(rowRole);
    setColumnRole(columnRole);
    setValueRole(valueRole);
    setRotationRole(rotationRole);
    setRowCategories(rowCategories);
    setColumnCategories(columnCategories);
}

/*!
 * Returns the index of the specified \a category in row categories list.
 * If the row categories list is empty, -1 is returned.
 * \note If the automatic row categories generation is in use, this method will
 * not return a valid index before the data in the model is resolved for the first time.
 */
int QItemModelBarDataProxy::rowCategoryIndex(const QString &category)
{
    return dptr()->m_rowCategories.indexOf(category);
}

/*!
 * Returns the index of the specified \a category in column categories list.
 * If the category is not found, -1 is returned.
 * \note If the automatic column categories generation is in use, this method will
 * not return a valid index before the data in the model is resolved for the first time.
 */
int QItemModelBarDataProxy::columnCategoryIndex(const QString &category)
{
    return dptr()->m_columnCategories.indexOf(category);
}

/*!
 * \property QItemModelBarDataProxy::rowRolePattern
 *
 * \brief Whether a search and replace is performed on the value mapped by row
 *  role before it is used as a row category.
 *
 * This property specifies the regular expression to find the portion of the
 * mapped value to replace and rowRoleReplace property contains the replacement string.
 * This is useful for example in parsing row and column categories from a single
 * timestamp field in the item model.
 *
 * \sa rowRole, rowRoleReplace
 */
void QItemModelBarDataProxy::setRowRolePattern(const QRegularExpression &pattern)
{
    if (dptr()->m_rowRolePattern != pattern) {
        dptr()->m_rowRolePattern = pattern;
        emit rowRolePatternChanged(pattern);
    }
}

QRegularExpression QItemModelBarDataProxy::rowRolePattern() const
{
    return dptrc()->m_rowRolePattern;
}

/*!
 * \property QItemModelBarDataProxy::columnRolePattern
 *
 * \brief Whether a search and replace is done on the value mapped by column
 * role before it is used as a column category.
 *
 * This property specifies the regular expression to find the portion of the
 * mapped value to replace and columnRoleReplace property contains the replacement string.
 * This is useful for example in parsing row and column categories from
 * a single timestamp field in the item model.
 *
 * \sa columnRole, columnRoleReplace
 */
void QItemModelBarDataProxy::setColumnRolePattern(const QRegularExpression &pattern)
{
    if (dptr()->m_columnRolePattern != pattern) {
        dptr()->m_columnRolePattern = pattern;
        emit columnRolePatternChanged(pattern);
    }
}

QRegularExpression QItemModelBarDataProxy::columnRolePattern() const
{
    return dptrc()->m_columnRolePattern;
}

/*!
 * \property QItemModelBarDataProxy::valueRolePattern
 *
 * \brief Whether a search and replace is done on the value mapped by value role
 * before it is used as a bar value.
 *
 * This property specifies the regular expression to find the portion of the
 * mapped value to replace and valueRoleReplace property contains the replacement string.
 *
 * \sa valueRole, valueRoleReplace
 */
void QItemModelBarDataProxy::setValueRolePattern(const QRegularExpression &pattern)
{
    if (dptr()->m_valueRolePattern != pattern) {
        dptr()->m_valueRolePattern = pattern;
        emit valueRolePatternChanged(pattern);
    }
}

QRegularExpression QItemModelBarDataProxy::valueRolePattern() const
{
    return dptrc()->m_valueRolePattern;
}

/*!
 * \property QItemModelBarDataProxy::rotationRolePattern
 *
 * \brief Whether a search and replace is done on the value mapped by rotation
 * role before it is used as a bar rotation angle.
 *
 * This property specifies the regular expression to find the portion
 * of the mapped value to replace and rotationRoleReplace property contains the replacement string.
 *
 * \sa rotationRole, rotationRoleReplace
 */
void QItemModelBarDataProxy::setRotationRolePattern(const QRegularExpression &pattern)
{
    if (dptr()->m_rotationRolePattern != pattern) {
        dptr()->m_rotationRolePattern = pattern;
        emit rotationRolePatternChanged(pattern);
    }
}

QRegularExpression QItemModelBarDataProxy::rotationRolePattern() const
{
    return dptrc()->m_rotationRolePattern;
}

/*!
 * \property QItemModelBarDataProxy::rowRoleReplace
 *
 * \brief The replace content to be used in conjunction with rowRolePattern.
 *
 * Defaults to empty string. For more information on how the search and replace using regular
 * expressions works, see QString::replace(const QRegularExpression &rx, const QString &after)
 * function documentation.
 *
 * \sa rowRole, rowRolePattern
 */
void QItemModelBarDataProxy::setRowRoleReplace(const QString &replace)
{
    if (dptr()->m_rowRoleReplace != replace) {
        dptr()->m_rowRoleReplace = replace;
        emit rowRoleReplaceChanged(replace);
    }
}

QString QItemModelBarDataProxy::rowRoleReplace() const
{
    return dptrc()->m_rowRoleReplace;
}

/*!
 * \property QItemModelBarDataProxy::columnRoleReplace
 *
 * \brief The replace content to be used in conjunction with columnRolePattern.
 *
 * Defaults to empty string. For more information on how the search and replace using regular
 * expressions works, see QString::replace(const QRegularExpression &rx, const QString &after)
 * function documentation.
 *
 * \sa columnRole, columnRolePattern
 */
void QItemModelBarDataProxy::setColumnRoleReplace(const QString &replace)
{
    if (dptr()->m_columnRoleReplace != replace) {
        dptr()->m_columnRoleReplace = replace;
        emit columnRoleReplaceChanged(replace);
    }
}

QString QItemModelBarDataProxy::columnRoleReplace() const
{
    return dptrc()->m_columnRoleReplace;
}

/*!
 * \property QItemModelBarDataProxy::valueRoleReplace
 *
 * \brief The replace content to be used in conjunction with valueRolePattern.
 *
 * Defaults to empty string. For more information on how the search and replace using regular
 * expressions works, see QString::replace(const QRegularExpression &rx, const QString &after)
 * function documentation.
 *
 * \sa valueRole, valueRolePattern
 */
void QItemModelBarDataProxy::setValueRoleReplace(const QString &replace)
{
    if (dptr()->m_valueRoleReplace != replace) {
        dptr()->m_valueRoleReplace = replace;
        emit valueRoleReplaceChanged(replace);
    }
}

QString QItemModelBarDataProxy::valueRoleReplace() const
{
    return dptrc()->m_valueRoleReplace;
}

/*!
 * \property QItemModelBarDataProxy::rotationRoleReplace
 *
 * \brief The replace content to be used in conjunction with
 * rotationRolePattern.
 *
 * Defaults to empty string. For more information on how the search and replace using regular
 * expressions works, see QString::replace(const QRegularExpression &rx, const QString &after)
 * function documentation.
 *
 * \sa rotationRole, rotationRolePattern
 */
void QItemModelBarDataProxy::setRotationRoleReplace(const QString &replace)
{
    if (dptr()->m_rotationRoleReplace != replace) {
        dptr()->m_rotationRoleReplace = replace;
        emit rotationRoleReplaceChanged(replace);
    }
}

QString QItemModelBarDataProxy::rotationRoleReplace() const
{
    return dptrc()->m_rotationRoleReplace;
}

/*!
 * \property QItemModelBarDataProxy::multiMatchBehavior
 *
 * \brief How multiple matches for each row/column combination are handled.
 *
 * Defaults to QItemModelBarDataProxy::MMBLast. The chosen behavior affects both bar value
 * and rotation.
 *
 * For example, you might have an item model with timestamped data taken at irregular intervals
 * and you want to visualize total value of data items on each day with a bar graph.
 * This can be done by specifying row and column categories so that each bar represents a day,
 * and setting multiMatchBehavior to QItemModelBarDataProxy::MMBCumulative.
 */
void QItemModelBarDataProxy::setMultiMatchBehavior(QItemModelBarDataProxy::MultiMatchBehavior behavior)
{
    if (dptr()->m_multiMatchBehavior != behavior) {
        dptr()->m_multiMatchBehavior = behavior;
        emit multiMatchBehaviorChanged(behavior);
    }
}

QItemModelBarDataProxy::MultiMatchBehavior QItemModelBarDataProxy::multiMatchBehavior() const
{
    return dptrc()->m_multiMatchBehavior;
}

/*!
 * \internal
 */
QItemModelBarDataProxyPrivate *QItemModelBarDataProxy::dptr()
{
    return static_cast<QItemModelBarDataProxyPrivate *>(d_ptr.data());
}

/*!
 * \internal
 */
const QItemModelBarDataProxyPrivate *QItemModelBarDataProxy::dptrc() const
{
    return static_cast<const QItemModelBarDataProxyPrivate *>(d_ptr.data());
}

// QItemModelBarDataProxyPrivate

QItemModelBarDataProxyPrivate::QItemModelBarDataProxyPrivate(QItemModelBarDataProxy *q)
    : QBarDataProxyPrivate(q),
      m_itemModelHandler(new BarItemModelHandler(q)),
      m_useModelCategories(false),
      m_autoRowCategories(true),
      m_autoColumnCategories(true),
      m_multiMatchBehavior(QItemModelBarDataProxy::MMBLast)
{
}

QItemModelBarDataProxyPrivate::~QItemModelBarDataProxyPrivate()
{
    delete m_itemModelHandler;
}

QItemModelBarDataProxy *QItemModelBarDataProxyPrivate::qptr()
{
    return static_cast<QItemModelBarDataProxy *>(q_ptr);
}

void QItemModelBarDataProxyPrivate::connectItemModelHandler()
{
    QObject::connect(m_itemModelHandler, &BarItemModelHandler::itemModelChanged,
                     qptr(), &QItemModelBarDataProxy::itemModelChanged);
    QObject::connect(qptr(), &QItemModelBarDataProxy::rowRoleChanged,
                     m_itemModelHandler, &AbstractItemModelHandler::handleMappingChanged);
    QObject::connect(qptr(), &QItemModelBarDataProxy::columnRoleChanged,
                     m_itemModelHandler, &AbstractItemModelHandler::handleMappingChanged);
    QObject::connect(qptr(), &QItemModelBarDataProxy::valueRoleChanged,
                     m_itemModelHandler, &AbstractItemModelHandler::handleMappingChanged);
    QObject::connect(qptr(), &QItemModelBarDataProxy::rotationRoleChanged,
                     m_itemModelHandler, &AbstractItemModelHandler::handleMappingChanged);
    QObject::connect(qptr(), &QItemModelBarDataProxy::rowCategoriesChanged,
                     m_itemModelHandler, &AbstractItemModelHandler::handleMappingChanged);
    QObject::connect(qptr(), &QItemModelBarDataProxy::columnCategoriesChanged,
                     m_itemModelHandler, &AbstractItemModelHandler::handleMappingChanged);
    QObject::connect(qptr(), &QItemModelBarDataProxy::useModelCategoriesChanged,
                     m_itemModelHandler, &AbstractItemModelHandler::handleMappingChanged);
    QObject::connect(qptr(), &QItemModelBarDataProxy::autoRowCategoriesChanged,
                     m_itemModelHandler, &AbstractItemModelHandler::handleMappingChanged);
    QObject::connect(qptr(), &QItemModelBarDataProxy::autoColumnCategoriesChanged,
                     m_itemModelHandler, &AbstractItemModelHandler::handleMappingChanged);
    QObject::connect(qptr(), &QItemModelBarDataProxy::rowRolePatternChanged,
                     m_itemModelHandler, &AbstractItemModelHandler::handleMappingChanged);
    QObject::connect(qptr(), &QItemModelBarDataProxy::columnRolePatternChanged,
                     m_itemModelHandler, &AbstractItemModelHandler::handleMappingChanged);
    QObject::connect(qptr(), &QItemModelBarDataProxy::valueRolePatternChanged,
                     m_itemModelHandler, &AbstractItemModelHandler::handleMappingChanged);
    QObject::connect(qptr(), &QItemModelBarDataProxy::rotationRolePatternChanged,
                     m_itemModelHandler, &AbstractItemModelHandler::handleMappingChanged);
    QObject::connect(qptr(), &QItemModelBarDataProxy::rowRoleReplaceChanged,
                     m_itemModelHandler, &AbstractItemModelHandler::handleMappingChanged);
    QObject::connect(qptr(), &QItemModelBarDataProxy::columnRoleReplaceChanged,
                     m_itemModelHandler, &AbstractItemModelHandler::handleMappingChanged);
    QObject::connect(qptr(), &QItemModelBarDataProxy::valueRoleReplaceChanged,
                     m_itemModelHandler, &AbstractItemModelHandler::handleMappingChanged);
    QObject::connect(qptr(), &QItemModelBarDataProxy::rotationRoleReplaceChanged,
                     m_itemModelHandler, &AbstractItemModelHandler::handleMappingChanged);
    QObject::connect(qptr(), &QItemModelBarDataProxy::multiMatchBehaviorChanged,
                     m_itemModelHandler, &AbstractItemModelHandler::handleMappingChanged);
}

QT_END_NAMESPACE
