universallistmodel.h 6.0 KB

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