/ proxyroles / switchrole.cpp
switchrole.cpp
  1  #include "switchrole.h"
  2  #include "qqmlsortfilterproxymodel.h"
  3  #include "filters/filter.h"
  4  #include <QtQml>
  5  
  6  namespace qqsfpm {
  7  
  8  /*!
  9      \qmltype SwitchRole
 10      \inherits SingleRole
 11      \inqmlmodule SortFilterProxyModel
 12      \ingroup ProxyRoles
 13      \ingroup FilterContainer
 14      \brief A role using \l Filter to conditionnaly compute its data.
 15  
 16      A SwitchRole is a \l ProxyRole that computes its data with the help of \l Filter.
 17      Each top level filters specified in the \l SwitchRole is evaluated on the rows of the model, if a \l Filter evaluates to true, the data of the \l SwitchRole for this row will be the one of the attached \l {value} {SwitchRole.value} property.
 18      If no top level filters evaluate to true, the data will default to the one of the \l defaultRoleName (or the \l defaultValue if no \l defaultRoleName is specified).
 19  
 20      In the following example, the \c favoriteOrFirstNameSection role is equal to \c * if the \c favorite role of a row is true, otherwise it's the same as the \c firstName role :
 21      \code
 22      SortFilterProxyModel {
 23         sourceModel: contactModel
 24         proxyRoles: SwitchRole {
 25             name: "favoriteOrFirstNameSection"
 26             filters: ValueFilter {
 27                 roleName: "favorite"
 28                 value: true
 29                 SwitchRole.value: "*"
 30             }
 31             defaultRoleName: "firstName"
 32          }
 33      }
 34      \endcode
 35      \sa FilterContainer
 36  */
 37  SwitchRoleAttached::SwitchRoleAttached(QObject* parent) : QObject (parent)
 38  {
 39      if (!qobject_cast<Filter*>(parent))
 40          qmlInfo(parent) << "SwitchRole must be attached to a Filter";
 41  }
 42  
 43  /*!
 44      \qmlattachedproperty var SwitchRole::value
 45  
 46      This property attaches a value to a \l Filter.
 47  */
 48  QVariant SwitchRoleAttached::value() const
 49  {
 50      return m_value;
 51  }
 52  
 53  void SwitchRoleAttached::setValue(const QVariant &value)
 54  {
 55      if (m_value == value)
 56          return;
 57  
 58      m_value = value;
 59      Q_EMIT valueChanged();
 60  }
 61  
 62  /*!
 63      \qmlproperty string SwitchRole::defaultRoleName
 64  
 65      This property holds the default role name of the role.
 66      If no filter match a row, the data of this role will be the data of the role whose name is \c defaultRoleName.
 67  */
 68  QString SwitchRole::defaultRoleName() const
 69  {
 70      return m_defaultRoleName;
 71  }
 72  
 73  void SwitchRole::setDefaultRoleName(const QString& defaultRoleName)
 74  {
 75      if (m_defaultRoleName == defaultRoleName)
 76          return;
 77  
 78      m_defaultRoleName = defaultRoleName;
 79      Q_EMIT defaultRoleNameChanged();
 80      invalidate();
 81  }
 82  
 83  /*!
 84      \qmlproperty var SwitchRole::defaultValue
 85  
 86      This property holds the default value of the role.
 87      If no filter match a row, and no \l defaultRoleName is set, the data of this role will be \c defaultValue.
 88  */
 89  QVariant SwitchRole::defaultValue() const
 90  {
 91      return m_defaultValue;
 92  }
 93  
 94  void SwitchRole::setDefaultValue(const QVariant& defaultValue)
 95  {
 96      if (m_defaultValue == defaultValue)
 97          return;
 98  
 99      m_defaultValue = defaultValue;
100      Q_EMIT defaultValueChanged();
101      invalidate();
102  }
103  
104  /*!
105      \qmlproperty list<Filter> SwitchRole::filters
106      \default
107  
108      This property holds the list of filters for this proxy role.
109      The data of this role will be equal to the attached \l {value} {SwitchRole.value} property of the first filter that matches the model row.
110  
111      \sa Filter, FilterContainer
112  */
113  
114  void SwitchRole::proxyModelCompleted(const QQmlSortFilterProxyModel& proxyModel)
115  {
116      for (Filter* filter : qAsConst(m_filters))
117          filter->proxyModelCompleted(proxyModel);
118  }
119  
120  SwitchRoleAttached* SwitchRole::qmlAttachedProperties(QObject* object)
121  {
122      return new SwitchRoleAttached(object);
123  }
124  
125  QVariant SwitchRole::data(const QModelIndex &sourceIndex, const QQmlSortFilterProxyModel &proxyModel)
126  {
127      for (auto filter: qAsConst(m_filters)) {
128          if (!filter->enabled())
129              continue;
130          if (filter->filterAcceptsRow(sourceIndex, proxyModel)) {
131              auto attached = static_cast<SwitchRoleAttached*>(qmlAttachedPropertiesObject<SwitchRole>(filter, false));
132              if (!attached) {
133                  qWarning() << "No SwitchRole.value provided for this filter" << filter;
134                  continue;
135              }
136              QVariant value = attached->value();
137              if (!value.isValid()) {
138                  qWarning() << "No SwitchRole.value provided for this filter" << filter;
139                  continue;
140              }
141              return value;
142          }
143      }
144      if (!m_defaultRoleName.isEmpty())
145          return proxyModel.sourceData(sourceIndex, m_defaultRoleName);
146      return m_defaultValue;
147  }
148  
149  void SwitchRole::onFilterAppended(Filter *filter)
150  {
151      connect(filter, &Filter::invalidated, this, &SwitchRole::invalidate);
152      auto attached = static_cast<SwitchRoleAttached*>(qmlAttachedPropertiesObject<SwitchRole>(filter, true));
153      connect(attached, &SwitchRoleAttached::valueChanged, this, &SwitchRole::invalidate);
154      invalidate();
155  }
156  
157  void SwitchRole::onFilterRemoved(Filter *filter)
158  {
159      Q_UNUSED(filter)
160      invalidate();
161  }
162  
163  void SwitchRole::onFiltersCleared()
164  {
165      invalidate();
166  }
167  
168  }