QATLControlsTreeModel.cpp 13 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367
  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 <QATLControlsTreeModel.h>
  9. #include <ACEEnums.h>
  10. #include <AudioControl.h>
  11. #include <AudioControlsEditorUndo.h>
  12. #include <IEditor.h>
  13. #include <QAudioControlTreeWidget.h>
  14. #include <QStandardItem>
  15. #include <QMessageBox>
  16. namespace AudioControls
  17. {
  18. //-------------------------------------------------------------------------------------------//
  19. QATLTreeModel::QATLTreeModel()
  20. : m_pControlsModel(nullptr)
  21. {
  22. }
  23. //-------------------------------------------------------------------------------------------//
  24. QATLTreeModel::~QATLTreeModel()
  25. {
  26. if (m_pControlsModel)
  27. {
  28. m_pControlsModel->RemoveListener(this);
  29. }
  30. }
  31. //-------------------------------------------------------------------------------------------//
  32. void QATLTreeModel::Initialize(CATLControlsModel* pControlsModel)
  33. {
  34. m_pControlsModel = pControlsModel;
  35. m_pControlsModel->AddListener(this);
  36. }
  37. //-------------------------------------------------------------------------------------------//
  38. QStandardItem* QATLTreeModel::GetItemFromControlID(CID nID)
  39. {
  40. QModelIndexList indexes = match(index(0, 0, QModelIndex()), eDR_ID, nID, 1, Qt::MatchRecursive);
  41. if (!indexes.empty())
  42. {
  43. return itemFromIndex(indexes.at(0));
  44. }
  45. return nullptr;
  46. }
  47. //-------------------------------------------------------------------------------------------//
  48. QStandardItem* QATLTreeModel::AddControl(CATLControl* pControl, QStandardItem* pParent, int nRow)
  49. {
  50. if (pControl && pParent)
  51. {
  52. QStandardItem* pItem = new QAudioControlItem(QString(pControl->GetName().c_str()), pControl);
  53. if (pItem)
  54. {
  55. pParent->insertRow(nRow, pItem);
  56. SetItemAsDirty(pItem);
  57. }
  58. return pItem;
  59. }
  60. return nullptr;
  61. }
  62. //-------------------------------------------------------------------------------------------//
  63. QStandardItem* QATLTreeModel::CreateFolder(QStandardItem* pParent, const AZStd::string_view sName, int nRow)
  64. {
  65. if (pParent)
  66. {
  67. // Make a valid name for the folder (avoid having folders with the same name under same root)
  68. QString sRootName(sName.data());
  69. QString sFolderName(sRootName);
  70. int number = 1;
  71. bool bFoundName = false;
  72. while (!bFoundName)
  73. {
  74. bFoundName = true;
  75. const int size = pParent->rowCount();
  76. for (int i = 0; i < size; ++i)
  77. {
  78. QStandardItem* pItem = pParent->child(i);
  79. if (pItem && (pItem->data(eDR_TYPE) == eIT_FOLDER) && (QString::compare(sFolderName, pItem->text(), Qt::CaseInsensitive) == 0))
  80. {
  81. bFoundName = false;
  82. sFolderName = sRootName + "_" + QString::number(number);
  83. ++number;
  84. break;
  85. }
  86. }
  87. }
  88. if (!sFolderName.isEmpty())
  89. {
  90. if (QStandardItem* pFolderItem = new QFolderItem(sFolderName))
  91. {
  92. SetItemAsDirty(pFolderItem);
  93. pParent->insertRow(nRow, pFolderItem);
  94. if (!CUndo::IsSuspended())
  95. {
  96. CUndo undo("Audio Folder Created");
  97. CUndo::Record(new CUndoFolderAdd(pFolderItem));
  98. }
  99. return pFolderItem;
  100. }
  101. }
  102. }
  103. return nullptr;
  104. }
  105. //-------------------------------------------------------------------------------------------//
  106. void QATLTreeModel::RemoveItem(QModelIndex index)
  107. {
  108. QModelIndexList indexList;
  109. indexList.push_back(index);
  110. RemoveItems(indexList);
  111. }
  112. //-------------------------------------------------------------------------------------------//
  113. void QATLTreeModel::RemoveItems(QModelIndexList indexList)
  114. {
  115. // Sort the controls by the level they are inside the tree
  116. // (the deepest in the tree first) and then by their row number.
  117. // This way we guarantee we don't delete the parent of a
  118. // control before its children
  119. struct STreeIndex
  120. {
  121. QPersistentModelIndex m_index;
  122. int m_level;
  123. STreeIndex(QPersistentModelIndex index, int level)
  124. : m_index(index)
  125. , m_level(level) {}
  126. bool operator< (const STreeIndex& index) const
  127. {
  128. if (m_level == index.m_level)
  129. {
  130. return m_index.row() > index.m_index.row();
  131. }
  132. return m_level > index.m_level;
  133. }
  134. };
  135. AZStd::vector<STreeIndex> sortedIndexList;
  136. const int size = indexList.length();
  137. for (int i = 0; i < size; ++i)
  138. {
  139. int level = 0;
  140. QModelIndex index = indexList[i];
  141. while (index.isValid())
  142. {
  143. ++level;
  144. index = index.parent();
  145. }
  146. sortedIndexList.push_back(STreeIndex(indexList[i], level));
  147. }
  148. std::sort(sortedIndexList.begin(), sortedIndexList.end());
  149. for (int i = 0; i < size; ++i)
  150. {
  151. QModelIndex index = sortedIndexList[i].m_index;
  152. if (index.isValid())
  153. {
  154. DeleteInternalData(index);
  155. // Mark parent as modified
  156. QModelIndex parent = index.parent();
  157. if (parent.isValid())
  158. {
  159. SetItemAsDirty(itemFromIndex(parent));
  160. }
  161. removeRow(index.row(), index.parent());
  162. }
  163. }
  164. }
  165. //-------------------------------------------------------------------------------------------//
  166. void QATLTreeModel::DeleteInternalData(QModelIndex root)
  167. {
  168. // Delete children first and in reverse order
  169. // of their row (so that we can undo them in the same order)
  170. AZStd::vector<QModelIndex> childs;
  171. QModelIndex child = index(0, 0, root);
  172. for (int i = 1; child.isValid(); ++i)
  173. {
  174. childs.push_back(child);
  175. child = index(i, 0, root);
  176. }
  177. const size_t size = childs.size();
  178. for (size_t i = 0; i < size; ++i)
  179. {
  180. DeleteInternalData(childs[(size - 1) - i]);
  181. }
  182. if (root.data(eDR_TYPE) == eIT_AUDIO_CONTROL)
  183. {
  184. m_pControlsModel->RemoveControl(root.data(eDR_ID).toUInt());
  185. }
  186. else
  187. {
  188. if (!CUndo::IsSuspended())
  189. {
  190. CUndo::Record(new CUndoFolderRemove(itemFromIndex(root)));
  191. }
  192. }
  193. }
  194. //-------------------------------------------------------------------------------------------//
  195. CATLControl* QATLTreeModel::GetControlFromIndex(QModelIndex index)
  196. {
  197. if (m_pControlsModel && index.isValid() && (index.data(eDR_TYPE) == eIT_AUDIO_CONTROL))
  198. {
  199. return m_pControlsModel->GetControlByID(index.data(eDR_ID).toUInt());
  200. }
  201. return nullptr;
  202. }
  203. //-------------------------------------------------------------------------------------------//
  204. void QATLTreeModel::OnControlModified(CATLControl* pControl)
  205. {
  206. if (pControl)
  207. {
  208. if (QStandardItem* pItem = GetItemFromControlID(pControl->GetId()))
  209. {
  210. QString sNewName(pControl->GetName().c_str());
  211. if (pItem->text() != sNewName)
  212. {
  213. pItem->setText(sNewName);
  214. }
  215. SetItemAsDirty(pItem);
  216. }
  217. }
  218. }
  219. //-------------------------------------------------------------------------------------------//
  220. void QATLTreeModel::SetItemAsDirty(QStandardItem* pItem)
  221. {
  222. if (pItem)
  223. {
  224. blockSignals(true);
  225. pItem->setData(true, eDR_MODIFIED);
  226. blockSignals(false);
  227. SetItemAsDirty(pItem->parent());
  228. }
  229. }
  230. //-------------------------------------------------------------------------------------------//
  231. CATLControl* QATLTreeModel::CreateControl(EACEControlType eControlType, const AZStd::string_view sName, CATLControl* pParent)
  232. {
  233. AZStd::string sFinalName = m_pControlsModel->GenerateUniqueName(sName, eControlType, pParent ? pParent->GetScope() : "", pParent);
  234. return m_pControlsModel->CreateControl(sFinalName, eControlType, pParent);
  235. }
  236. //-------------------------------------------------------------------------------------------//
  237. bool QATLTreeModel::dropMimeData(const QMimeData* mimeData, Qt::DropAction action, int row, int column, const QModelIndex& parent)
  238. {
  239. // LY-17684
  240. QStandardItem* rootItem = invisibleRootItem();
  241. QStandardItem* targetItem = rootItem;
  242. if (parent.isValid())
  243. {
  244. targetItem = itemFromIndex(parent);
  245. }
  246. if (targetItem)
  247. {
  248. if (targetItem && (targetItem->data(eDR_TYPE) == eIT_FOLDER || targetItem == rootItem))
  249. {
  250. const QString format = "application/x-qabstractitemmodeldatalist";
  251. if (mimeData->hasFormat(format))
  252. {
  253. QByteArray encoded = mimeData->data(format);
  254. QDataStream stream(&encoded, QIODevice::ReadOnly);
  255. while (!stream.atEnd())
  256. {
  257. int streamRow, streamCol;
  258. QMap<int, QVariant> roleDataMap;
  259. stream >> streamRow >> streamCol >> roleDataMap;
  260. if (!roleDataMap.isEmpty())
  261. {
  262. // If dropping a folder, make sure that folder name doesn't already exist where it is being dropped
  263. if (roleDataMap[eDR_TYPE] == eIT_FOLDER)
  264. {
  265. // Make sure the target folder doesn't have a folder with the same name
  266. QString droppedFolderName = roleDataMap[Qt::DisplayRole].toString();
  267. const int size = targetItem->rowCount();
  268. for (int i = 0; i < size; ++i)
  269. {
  270. QStandardItem* pItem = targetItem->child(i);
  271. if (pItem && (pItem->data(eDR_TYPE) == eIT_FOLDER) && (QString::compare(droppedFolderName, pItem->text(), Qt::CaseInsensitive) == 0))
  272. {
  273. QMessageBox messageBox;
  274. messageBox.setStandardButtons(QMessageBox::Ok);
  275. messageBox.setWindowTitle("Audio Controls Editor");
  276. messageBox.setText("This destination already contains a folder named '" + droppedFolderName + "'.");
  277. messageBox.exec();
  278. return false;
  279. }
  280. }
  281. }
  282. }
  283. }
  284. }
  285. }
  286. }
  287. if (mimeData && action == Qt::MoveAction)
  288. {
  289. if (!CUndo::IsSuspended())
  290. {
  291. CUndo undo("Audio Control Moved");
  292. CUndo::Record(new CUndoItemMove());
  293. }
  294. }
  295. return QStandardItemModel::dropMimeData(mimeData, action, row, column, parent);
  296. }
  297. //-------------------------------------------------------------------------------------------//
  298. bool QATLTreeModel::canDropMimeData(const QMimeData* mimeData, Qt::DropAction action, int row, int column, const QModelIndex& parent) const
  299. {
  300. if (!parent.isValid())
  301. {
  302. // Prevent moving controls to the root (outside a folder)
  303. const QString format = "application/x-qabstractitemmodeldatalist";
  304. if (mimeData->hasFormat(format))
  305. {
  306. QByteArray data = mimeData->data(format);
  307. QDataStream stream(&data, QIODevice::ReadOnly);
  308. int streamRow, streamCol;
  309. QMap<int, QVariant> roleDataMap;
  310. stream >> streamRow >> streamCol >> roleDataMap;
  311. if (!roleDataMap.isEmpty() && roleDataMap[eDR_TYPE] != eIT_FOLDER)
  312. {
  313. return false;
  314. }
  315. }
  316. }
  317. else if (parent.data(eDR_TYPE) == eIT_AUDIO_CONTROL)
  318. {
  319. // Prevent dropping on switches
  320. CID nID = parent.data(eDR_ID).toUInt();
  321. if (CATLControl* pControl = m_pControlsModel->GetControlByID(nID))
  322. {
  323. EACEControlType eType = pControl->GetType();
  324. if (eType == eACET_SWITCH || eType == eACET_SWITCH_STATE)
  325. {
  326. return false;
  327. }
  328. }
  329. }
  330. return QStandardItemModel::canDropMimeData(mimeData, action, row, column, parent);
  331. }
  332. } // namespace AudioControls