universallistmodel.h 5.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201
  1. #pragma once
  2. #include <universallistmodelbase.h>
  3. #include <QObject>
  4. #include <QList>
  5. #include <QHash>
  6. #include <QPointer>
  7. #include <QMetaProperty>
  8. #include <QMetaObject>
  9. #include <QDebug>
  10. /*!
  11. * \brief Universal list model is QObject-base list model abstraction.
  12. * It exposes all objects properties as data-roles.
  13. */
  14. template <typename T>
  15. class UniversalListModel : public UniversalListModelBase
  16. {
  17. public:
  18. UniversalListModel(QObject* parent = 0) : UniversalListModelBase(parent) {}
  19. ~UniversalListModel() {
  20. clear();
  21. }
  22. int rowCount(const QModelIndex &parent) const override {
  23. Q_UNUSED(parent)
  24. return count();
  25. }
  26. int count() const override {
  27. return m_container.count();
  28. }
  29. QHash<int, QByteArray> roleNames() const override {
  30. if(s_roleNames.isEmpty()) {
  31. int propertyCount = T::staticMetaObject.propertyCount();
  32. for(int i = 1; i < propertyCount; i++) {
  33. s_roleNames.insert(Qt::UserRole + i, T::staticMetaObject.property(i).name());
  34. }
  35. s_roleNames[propertyCount] = "modelData";
  36. }
  37. return s_roleNames;
  38. }
  39. QVariant data(const QModelIndex &index, int role) const override
  40. {
  41. int row = index.row();
  42. if(row < 0 || row >= m_container.count() || m_container.at(row).isNull()) {
  43. return QVariant();
  44. }
  45. T* dataPtr = m_container.at(row).data();
  46. if(s_roleNames.value(role) == "modelData") {
  47. return QVariant::fromValue(dataPtr);
  48. }
  49. return dataPtr->property(s_roleNames.value(role));
  50. }
  51. /*!
  52. * \brief append
  53. * \param value
  54. * \return
  55. */
  56. int append(T* value) {
  57. Q_ASSERT_X(value != nullptr, fullTemplateName(), "Trying to add member of NULL");
  58. if(m_container.indexOf(value) >= 0) {
  59. #ifdef DEBUG
  60. qDebug() << fullTemplateName() << "Member already exists";
  61. #endif
  62. return -1;
  63. }
  64. beginInsertRows(QModelIndex(), m_container.count(), m_container.count());
  65. m_container.append(QPointer<T>(value));
  66. emit countChanged();
  67. endInsertRows();
  68. return m_container.count() - 1;
  69. }
  70. /*!
  71. * \brief prepend
  72. * \param value
  73. * \return
  74. */
  75. int prepend(T* value) {
  76. Q_ASSERT_X(value != nullptr, fullTemplateName(), "Trying to add member of NULL");
  77. if(m_container.indexOf(value) >= 0) {
  78. #ifdef DEBUG
  79. qDebug() << fullTemplateName() << "Member already exists";
  80. #endif
  81. return -1;
  82. }
  83. beginInsertRows(QModelIndex(), 0, 0);
  84. m_container.prepend(QPointer<T>(value));
  85. emit countChanged();
  86. endInsertRows();
  87. return 0;
  88. }
  89. /*!
  90. * \brief remove
  91. * \param value
  92. */
  93. void remove(T* value) {
  94. Q_ASSERT_X(value != nullptr, fullTemplateName(), ": Trying to remove member of NULL");
  95. int valueIndex = m_container.indexOf(value);
  96. remove(valueIndex);
  97. }
  98. void remove(int valueIndex) override {
  99. if(valueIndex >= 0) {
  100. beginRemoveRows(QModelIndex(), valueIndex, valueIndex);
  101. m_container.removeAt(valueIndex);
  102. emit countChanged();
  103. endRemoveRows();
  104. }
  105. }
  106. /*!
  107. * \brief Resets container with new container passed as parameter
  108. * \param container a data for model. Should contain QPointer's to objects.
  109. * Passing empty container makes model empty. This method should be used to cleanup model.
  110. */
  111. void reset(const QList<QPointer<T> >& container) {
  112. beginResetModel();
  113. clear();
  114. m_container = container;
  115. emit countChanged();
  116. endResetModel();
  117. }
  118. /*!
  119. * \brief Returns the item at index position i in the list. i must be a valid index position in the list (i.e., 0 <= i < rowCount()).
  120. * This function is very fast (constant time).
  121. * \param i index of looking object
  122. * \return Object at provided index
  123. */
  124. T* at(int i) const {
  125. return m_container.at(i);
  126. }
  127. /*!
  128. * \brief Looking for index of objec
  129. * \param value
  130. * \return
  131. */
  132. int indexOf(T* value) const {
  133. return m_container.indexOf(value);
  134. }
  135. /*!
  136. * \brief findByProperty method finds item in internal container property of that is provided value
  137. * \param propertyName Latin1 name of looking property
  138. * \param value property of corresponded type inside QVariant container
  139. * \return
  140. */
  141. QPointer<T> findByProperty(const char* propertyName, const QVariant& value) const {
  142. auto iter = std::find_if(m_container.begin(), m_container.end(), [=](const QPointer<T> &item) -> bool {
  143. return item->property(propertyName) == value;
  144. });
  145. if(iter != m_container.end()) {
  146. return *iter;
  147. }
  148. return QPointer<T>();
  149. }
  150. /*!
  151. * \brief container returns internal container
  152. * \return
  153. */
  154. QList<QPointer<T> > container() const {
  155. return m_container;
  156. }
  157. protected:
  158. void clear() {
  159. m_container.clear();
  160. emit countChanged();
  161. }
  162. QList<QPointer<T> > m_container;
  163. static QHash<int, QByteArray> s_roleNames;
  164. private:
  165. static QByteArray fullTemplateName() { //Debug helper
  166. return QString("UniversalListModel<%1>").arg(T::staticMetaObject.className()).toLatin1();
  167. }
  168. };
  169. template<typename T>
  170. QHash<int, QByteArray> UniversalListModel<T>::s_roleNames;