AbstractGroupProxyModel.cpp 12 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398
  1. /*
  2. * Copyright (c) Contributors to the Open 3D Engine Project.
  3. * For complete copyright and license terms please see the LICENSE at the root of this distribution.
  4. *
  5. * SPDX-License-Identifier: Apache-2.0 OR MIT
  6. *
  7. */
  8. #include "EditorDefs.h"
  9. #include "AbstractGroupProxyModel.h"
  10. AbstractGroupProxyModel::AbstractGroupProxyModel(QObject* parent)
  11. : QAbstractProxyModel(parent)
  12. {
  13. }
  14. AbstractGroupProxyModel::~AbstractGroupProxyModel()
  15. {
  16. }
  17. QVariant AbstractGroupProxyModel::data(const QModelIndex& index, int role) const
  18. {
  19. if (!index.isValid())
  20. {
  21. return QVariant();
  22. }
  23. const GroupItem* group = reinterpret_cast<GroupItem*>(index.internalPointer());
  24. if (index.row() >= group->subGroups.count())
  25. {
  26. return sourceModel()->data(mapToSource(index), role);
  27. }
  28. else if (role == Qt::DisplayRole && index.column() == 0 && !group->subGroups.at(index.row())->groupTitle.isEmpty())
  29. {
  30. return group->subGroups[index.row()]->groupTitle;
  31. }
  32. else if (group->subGroups.at(index.row())->groupSourceIndex.isValid())
  33. {
  34. return group->subGroups.at(index.row())->groupSourceIndex.data(role);
  35. }
  36. return QVariant();
  37. }
  38. int AbstractGroupProxyModel::rowCount(const QModelIndex& parent) const
  39. {
  40. if (!sourceModel())
  41. {
  42. return 0;
  43. }
  44. // invalid parent - root item is used
  45. if (!parent.isValid())
  46. {
  47. return m_rootItem.subGroups.count() + m_rootItem.sourceIndexes.count();
  48. }
  49. // this is the group the parent is in.
  50. const GroupItem* group = reinterpret_cast<GroupItem*>(parent.internalPointer());
  51. if (parent.row() < group->subGroups.count())
  52. {
  53. return group->subGroups[parent.row()]->subGroups.count() + group->subGroups[parent.row()]->sourceIndexes.count();
  54. }
  55. return 0;
  56. }
  57. int AbstractGroupProxyModel::columnCount(const QModelIndex& parent) const
  58. {
  59. Q_UNUSED(parent)
  60. if (!sourceModel())
  61. {
  62. return 0;
  63. }
  64. return sourceModel()->columnCount(QModelIndex());
  65. }
  66. QModelIndex AbstractGroupProxyModel::index(int row, int column, const QModelIndex& parent) const
  67. {
  68. if (row >= rowCount(parent) || column >= columnCount(parent))
  69. {
  70. return QModelIndex();
  71. }
  72. if (!parent.isValid())
  73. {
  74. return createIndex(row, column, const_cast<GroupItem*>(&m_rootItem));
  75. }
  76. const GroupItem* group = reinterpret_cast<GroupItem*>(parent.internalPointer());
  77. GroupItem* newParent = group->subGroups[parent.row()];
  78. return createIndex(row, column, newParent);
  79. }
  80. QVariant AbstractGroupProxyModel::headerData(int section, Qt::Orientation orientation, int role) const
  81. {
  82. return sourceModel()->headerData(section, orientation, role);
  83. }
  84. QModelIndex AbstractGroupProxyModel::parent(const QModelIndex& index) const
  85. {
  86. GroupItem* group = reinterpret_cast<GroupItem*>(index.internalPointer());
  87. if (!group)
  88. {
  89. return QModelIndex();
  90. }
  91. const GroupItem* parentGroup = FindGroup(group);
  92. if (!parentGroup)
  93. {
  94. return QModelIndex();
  95. }
  96. const int row = parentGroup->subGroups.indexOf(group);
  97. return createIndex(row, 0, const_cast<GroupItem*>(parentGroup));
  98. }
  99. bool AbstractGroupProxyModel::hasChildren(const QModelIndex& parent) const
  100. {
  101. if (!parent.isValid())
  102. {
  103. return true;
  104. }
  105. const GroupItem* group = reinterpret_cast<GroupItem*>(parent.internalPointer());
  106. return parent.row() < group->subGroups.count();
  107. }
  108. Qt::ItemFlags AbstractGroupProxyModel::flags(const QModelIndex& index) const
  109. {
  110. const QModelIndex sourceIndex = mapToSource(index);
  111. if (!sourceIndex.isValid())
  112. {
  113. return Qt::ItemIsEnabled | Qt::ItemIsSelectable;
  114. }
  115. return sourceModel()->flags(sourceIndex);
  116. }
  117. QModelIndex AbstractGroupProxyModel::mapToSource(const QModelIndex& proxyIndex) const
  118. {
  119. GroupItem* group = reinterpret_cast<GroupItem*>(proxyIndex.internalPointer());
  120. if (!group)
  121. {
  122. return QModelIndex();
  123. }
  124. const int i = proxyIndex.row() - group->subGroups.count();
  125. if (i < 0)
  126. {
  127. return QModelIndex();
  128. }
  129. return group->sourceIndexes[i].sibling(group->sourceIndexes[i].row(), proxyIndex.column());
  130. }
  131. QModelIndex AbstractGroupProxyModel::mapFromSource(const QModelIndex& sourceIndex) const
  132. {
  133. if (!sourceIndex.isValid())
  134. {
  135. return QModelIndex();
  136. }
  137. GroupItem* group = FindIndex(sourceIndex.sibling(sourceIndex.row(), 0));
  138. if (!group)
  139. {
  140. return QModelIndex();
  141. }
  142. if (group->groupSourceIndex == sourceIndex)
  143. {
  144. GroupItem* parentGroup = FindGroup(group);
  145. return createIndex(parentGroup->subGroups.indexOf(group), sourceIndex.column(), parentGroup);
  146. }
  147. return createIndex(group->subGroups.count() + group->sourceIndexes.indexOf(sourceIndex.sibling(sourceIndex.row(), 0)),
  148. sourceIndex.column(), const_cast<GroupItem*>(group));
  149. }
  150. AbstractGroupProxyModel::GroupItem* AbstractGroupProxyModel::FindIndex(const QModelIndex& index, GroupItem* group) const
  151. {
  152. if (group == nullptr)
  153. {
  154. group = const_cast<GroupItem*>(&m_rootItem);
  155. }
  156. if (group->sourceIndexes.contains(index) || group->groupSourceIndex == index)
  157. {
  158. return group;
  159. }
  160. for (GroupItem* subGroup : group->subGroups)
  161. {
  162. GroupItem* g = FindIndex(index, subGroup);
  163. if (g)
  164. {
  165. return g;
  166. }
  167. }
  168. return nullptr;
  169. }
  170. AbstractGroupProxyModel::GroupItem* AbstractGroupProxyModel::FindGroup(GroupItem* group, GroupItem* parent) const
  171. {
  172. if (parent == nullptr)
  173. {
  174. parent = const_cast<GroupItem*>(&m_rootItem);
  175. }
  176. if (parent->subGroups.contains(group))
  177. {
  178. return parent;
  179. }
  180. for (GroupItem* subGroup : parent->subGroups)
  181. {
  182. GroupItem* g = FindGroup(group, subGroup);
  183. if (g)
  184. {
  185. return g;
  186. }
  187. }
  188. return nullptr;
  189. }
  190. void AbstractGroupProxyModel::setSourceModel(QAbstractItemModel* sourceModel)
  191. {
  192. QAbstractProxyModel::setSourceModel(sourceModel);
  193. connect(sourceModel, &QAbstractItemModel::rowsInserted, this, &AbstractGroupProxyModel::SourceRowsInserted);
  194. connect(sourceModel, &QAbstractItemModel::rowsAboutToBeRemoved, this, &AbstractGroupProxyModel::SourceRowsAboutToBeRemoved);
  195. connect(sourceModel, &QAbstractItemModel::dataChanged, this, &AbstractGroupProxyModel::SourceDataChanged);
  196. connect(sourceModel, &QAbstractItemModel::modelAboutToBeReset, this, &AbstractGroupProxyModel::slotSourceAboutToBeReset);
  197. connect(sourceModel, &QAbstractItemModel::modelReset, this, &AbstractGroupProxyModel::slotSourceReset);
  198. connect(sourceModel, &QAbstractItemModel::layoutAboutToBeChanged, this, &AbstractGroupProxyModel::slotSourceAboutToBeReset);
  199. connect(sourceModel, &QAbstractItemModel::layoutChanged, this, &AbstractGroupProxyModel::slotSourceReset);
  200. RebuildTree();
  201. }
  202. void AbstractGroupProxyModel::slotSourceAboutToBeReset()
  203. {
  204. beginResetModel();
  205. qDeleteAll(m_rootItem.subGroups);
  206. m_rootItem.subGroups.clear();
  207. m_rootItem.sourceIndexes.clear();
  208. }
  209. void AbstractGroupProxyModel::slotSourceReset()
  210. {
  211. const int rowCount = sourceModel() ? sourceModel()->rowCount() : 0;
  212. for (int row = 0; row < rowCount; ++row)
  213. {
  214. const QModelIndex sourceIndex = sourceModel()->index(row, 0);
  215. GroupItem* group = CreateGroupIfNotExists(GroupForSourceIndex(sourceIndex));
  216. if (IsGroupIndex(sourceIndex))
  217. {
  218. group->groupSourceIndex = sourceIndex;
  219. }
  220. else
  221. {
  222. group->sourceIndexes.push_back(sourceIndex);
  223. }
  224. }
  225. endResetModel();
  226. }
  227. void AbstractGroupProxyModel::RebuildTree()
  228. {
  229. beginResetModel();
  230. {
  231. QSignalBlocker blocker(this);
  232. slotSourceAboutToBeReset();
  233. slotSourceReset();
  234. }
  235. endResetModel();
  236. Q_EMIT GroupUpdated();
  237. }
  238. int AbstractGroupProxyModel::subGroupCount() const
  239. {
  240. return m_rootItem.subGroups.count();
  241. }
  242. void AbstractGroupProxyModel::SourceRowsInserted(const QModelIndex& p, int from, int to)
  243. {
  244. if (p.isValid())
  245. {
  246. return;
  247. }
  248. for (int row = from; row <= to; ++row)
  249. {
  250. const QModelIndex sourceIndex = sourceModel()->index(row, 0);
  251. GroupItem* group = CreateGroupIfNotExists(GroupForSourceIndex(sourceIndex));
  252. if (IsGroupIndex(sourceIndex))
  253. {
  254. group->groupSourceIndex = sourceIndex;
  255. }
  256. else
  257. {
  258. const int modelRow = group->subGroups.count() + group->sourceIndexes.count();
  259. beginInsertRows(parent(createIndex(0, 0, group)), modelRow, modelRow);
  260. group->sourceIndexes.push_back(sourceIndex);
  261. endInsertRows();
  262. }
  263. }
  264. Q_EMIT GroupUpdated();
  265. }
  266. void AbstractGroupProxyModel::SourceRowsAboutToBeRemoved(const QModelIndex& p, int from, int to)
  267. {
  268. if (p.isValid())
  269. {
  270. return;
  271. }
  272. for (int row = from; row <= to; ++row)
  273. {
  274. const QModelIndex sourceIndex = sourceModel()->index(row, 0);
  275. GroupItem* group = const_cast<GroupItem*>(FindIndex(sourceIndex));
  276. if (!group)
  277. {
  278. continue;
  279. }
  280. if (group->groupSourceIndex != sourceIndex)
  281. {
  282. const int modelRow = group->subGroups.count() + group->sourceIndexes.indexOf(sourceIndex);
  283. beginRemoveRows(parent(createIndex(0, 0, group)), modelRow, modelRow);
  284. group->sourceIndexes.remove(group->sourceIndexes.indexOf(sourceIndex));
  285. endRemoveRows();
  286. }
  287. RemoveEmptyGroup(group);
  288. }
  289. Q_EMIT GroupUpdated();
  290. }
  291. void AbstractGroupProxyModel::SourceDataChanged(const QModelIndex& topLeft, const QModelIndex& bottomRight)
  292. {
  293. if (topLeft.parent().isValid())
  294. {
  295. return;
  296. }
  297. for (int row = topLeft.row(); row <= bottomRight.row(); ++row)
  298. {
  299. const QModelIndex sourceIndex = sourceModel()->index(row, 0);
  300. const GroupItem* currentGroup = FindIndex(sourceIndex);
  301. GroupItem* newGroup = CreateGroupIfNotExists(GroupForSourceIndex(sourceIndex));
  302. if (currentGroup != newGroup)
  303. {
  304. SourceRowsAboutToBeRemoved(QModelIndex(), row, row);
  305. SourceRowsInserted(QModelIndex(), row, row);
  306. }
  307. else
  308. {
  309. emit dataChanged(mapFromSource(sourceIndex), mapFromSource(sourceIndex.sibling(row, columnCount() - 1)));
  310. }
  311. }
  312. Q_EMIT GroupUpdated();
  313. }
  314. AbstractGroupProxyModel::GroupItem* AbstractGroupProxyModel::CreateGroupIfNotExists(QStringList group)
  315. {
  316. GroupItem* currentGroup = &m_rootItem;
  317. while (true)
  318. {
  319. if (group.isEmpty())
  320. {
  321. return currentGroup;
  322. }
  323. auto matchingSubGroup = std::find_if(currentGroup->subGroups.begin(), currentGroup->subGroups.end(),
  324. [=](const GroupItem* g)
  325. {
  326. return QString::compare(g->groupTitle, group.first(), Qt::CaseInsensitive) == 0;
  327. }
  328. );
  329. if (matchingSubGroup == currentGroup->subGroups.end())
  330. {
  331. GroupItem* newGroup = new GroupItem;
  332. newGroup->groupTitle = group.first();
  333. beginInsertRows(parent(createIndex(0, 0, currentGroup)),
  334. currentGroup->subGroups.size(), currentGroup->subGroups.size());
  335. currentGroup->subGroups.push_back(newGroup);
  336. endInsertRows();
  337. currentGroup = currentGroup->subGroups[currentGroup->subGroups.size() - 1];
  338. }
  339. else
  340. {
  341. currentGroup = *matchingSubGroup;
  342. }
  343. group.pop_front();
  344. }
  345. }
  346. void AbstractGroupProxyModel::RemoveEmptyGroup(GroupItem* group)
  347. {
  348. if (!group->subGroups.isEmpty() || !group->sourceIndexes.isEmpty() || group == &m_rootItem
  349. || (group->groupSourceIndex.isValid() && !IsGroupIndex(group->groupSourceIndex)))
  350. {
  351. return;
  352. }
  353. GroupItem* parentGroup = const_cast<GroupItem*>(FindGroup(group));
  354. const int row = parentGroup->subGroups.indexOf(group);
  355. beginRemoveRows(parent(createIndex(0, 0, parentGroup)), row, row);
  356. delete parentGroup->subGroups.takeAt(row);
  357. endRemoveRows();
  358. RemoveEmptyGroup(parentGroup);
  359. }
  360. #include <Util/moc_AbstractGroupProxyModel.cpp>