AssetBundlerAbstractFileTableModel.cpp 8.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244
  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 <source/models/AssetBundlerAbstractFileTableModel.h>
  9. #include <source/utils/utils.h>
  10. #include <AzFramework/IO/LocalFileIO.h>
  11. #include <QSetIterator>
  12. namespace AssetBundler
  13. {
  14. const char* DateTimeFormat = "hh:mm:ss MMM dd, yyyy";
  15. const char* ReadOnlyFileErrorMessage = "File (%s) is Read-Only. Please check your version control and try again.";
  16. AssetBundlerAbstractFileTableModel::AssetBundlerAbstractFileTableModel(QObject* parent)
  17. : QAbstractTableModel(parent)
  18. {
  19. }
  20. void AssetBundlerAbstractFileTableModel::Reload(
  21. const char* fileExtension,
  22. const QSet<QString>& watchedFolders,
  23. const QSet<QString>& watchedFiles,
  24. const AZStd::unordered_map<AZStd::string, AZStd::string>& pathToProjectNameMap)
  25. {
  26. AZStd::vector<AZStd::string> keysToRemove = m_fileListKeys;
  27. // Reload all the files in the watched folders
  28. QString filter = QString("*.%1").arg(fileExtension);
  29. QSetIterator<QString> itr(watchedFolders);
  30. while (itr.hasNext())
  31. {
  32. QDir filesDir(itr.next());
  33. filesDir.setNameFilters({ filter });
  34. for (const QString& fileNameAndExtension : filesDir.entryList(QDir::Files))
  35. {
  36. AZStd::string absolutePath = filesDir.absoluteFilePath(fileNameAndExtension).toUtf8().data();
  37. AZStd::string projectName;
  38. if (pathToProjectNameMap.contains(absolutePath))
  39. {
  40. projectName = pathToProjectNameMap.at(absolutePath);
  41. }
  42. // If a project name is already specified, then the associated file is a default file
  43. LoadFile(absolutePath, projectName, !projectName.empty());
  44. keysToRemove.erase(
  45. AZStd::remove(keysToRemove.begin(), keysToRemove.end(), AssetBundler::GenerateKeyFromAbsolutePath(absolutePath)),
  46. keysToRemove.end());
  47. }
  48. }
  49. // Reload all the watched files
  50. for (const QString& filePath : watchedFiles)
  51. {
  52. AZStd::string absolutePath = filePath.toUtf8().data();
  53. if (AZ::IO::FileIOBase::GetInstance()->Exists(absolutePath.c_str()))
  54. {
  55. AZStd::string projectName;
  56. if (pathToProjectNameMap.contains(absolutePath))
  57. {
  58. projectName = pathToProjectNameMap.at(absolutePath);
  59. }
  60. // If a project name is already specified, then the associated file is a default file
  61. LoadFile(absolutePath, projectName, !projectName.empty());
  62. keysToRemove.erase(
  63. AZStd::remove(keysToRemove.begin(), keysToRemove.end(), AssetBundler::GenerateKeyFromAbsolutePath(absolutePath)),
  64. keysToRemove.end());
  65. }
  66. }
  67. //Remove nonexistant files from the model
  68. for (const AZStd::string& key : keysToRemove)
  69. {
  70. DeleteFileByKey(key);
  71. }
  72. }
  73. void AssetBundlerAbstractFileTableModel::ReloadFiles(
  74. const AZStd::vector<AZStd::string>& absoluteFilePathList,
  75. AZStd::unordered_map<AZStd::string, AZStd::string> pathToProjectNameMap)
  76. {
  77. for (const AZStd::string& absoluteFilePath : absoluteFilePathList)
  78. {
  79. if (!AZ::IO::FileIOBase::GetInstance()->Exists(absoluteFilePath.c_str()))
  80. {
  81. // File is not present on-disk, make sure to remove it from the model
  82. DeleteFileByKey(AssetBundler::GenerateKeyFromAbsolutePath(absoluteFilePath));
  83. continue;
  84. }
  85. // If a project name is already specified, then the associated file is a default file
  86. AZStd::string projectName = pathToProjectNameMap[absoluteFilePath];
  87. LoadFile(absoluteFilePath, projectName, !projectName.empty());
  88. }
  89. }
  90. bool AssetBundlerAbstractFileTableModel::Save(const QModelIndex& selectedIndex)
  91. {
  92. if (!selectedIndex.isValid() || m_keysWithUnsavedChanges.empty())
  93. {
  94. // There is nothing to save
  95. return true;
  96. }
  97. AZStd::string key = GetFileKey(selectedIndex);
  98. if (key.empty())
  99. {
  100. // Error has already been thrown
  101. return false;
  102. }
  103. // Save the file
  104. if (!WriteToDisk(key))
  105. {
  106. return false;
  107. }
  108. // Update the display
  109. m_keysWithUnsavedChanges.erase(key);
  110. QModelIndex topLeftIndex = index(selectedIndex.row(), 0);
  111. QModelIndex bottomRightIndex = index(selectedIndex.row(), columnCount() - 1);
  112. emit dataChanged(topLeftIndex, bottomRightIndex, { Qt::DisplayRole, Qt::FontRole });
  113. return true;
  114. }
  115. bool AssetBundlerAbstractFileTableModel::SaveAll()
  116. {
  117. if (!HasUnsavedChanges())
  118. {
  119. // No need to update all of the elements if we are not changing anything
  120. return true;
  121. }
  122. bool hasSaveErrors = false;
  123. // Save every file with unsaved changes
  124. AZStd::unordered_set<AZStd::string> keysWithErrors;
  125. for (const AZStd::string& key : m_keysWithUnsavedChanges)
  126. {
  127. if (!WriteToDisk(key))
  128. {
  129. // Error has already been thrown
  130. hasSaveErrors = true;
  131. keysWithErrors.emplace(key);
  132. }
  133. }
  134. m_keysWithUnsavedChanges = keysWithErrors;
  135. // Update the display of all elements
  136. QModelIndex firstIndex = index(0, 0);
  137. QModelIndex lastIndex = index(rowCount() - 1, columnCount() - 1);
  138. emit dataChanged(firstIndex, lastIndex, { Qt::DisplayRole, Qt::FontRole });
  139. return !hasSaveErrors;
  140. }
  141. bool AssetBundlerAbstractFileTableModel::HasUnsavedChanges() const
  142. {
  143. return !m_keysWithUnsavedChanges.empty();
  144. }
  145. int AssetBundlerAbstractFileTableModel::rowCount(const QModelIndex& /*parent*/) const
  146. {
  147. return static_cast<int>(m_fileListKeys.size());
  148. }
  149. AZStd::string AssetBundlerAbstractFileTableModel::GetFileKey(const QModelIndex& index) const
  150. {
  151. int row = index.row();
  152. int col = index.column();
  153. if (row >= rowCount() || row < 0 || col >= columnCount() || col < 0)
  154. {
  155. AZ_Error("AssetBundler", false, "Selected index (%i, %i) is out of range.", row, col);
  156. return {};
  157. }
  158. return m_fileListKeys.at(row);
  159. }
  160. const AZStd::vector<AZStd::string>& AssetBundlerAbstractFileTableModel::GetAllFileKeys() const
  161. {
  162. return m_fileListKeys;
  163. }
  164. int AssetBundlerAbstractFileTableModel::GetIndexRowByKey(const AZStd::string& key) const
  165. {
  166. auto it = AZStd::find(m_fileListKeys.begin(), m_fileListKeys.end(), key);
  167. return it == m_fileListKeys.end() ? -1 : static_cast<int>(AZStd::distance(m_fileListKeys.begin(), it));
  168. }
  169. void AssetBundlerAbstractFileTableModel::AddFileKey(const AZStd::string& key)
  170. {
  171. if (AZStd::find(m_fileListKeys.begin(), m_fileListKeys.end(), key) != m_fileListKeys.end())
  172. {
  173. // Key already exists. This could happen when we update existing entires.
  174. return;
  175. }
  176. beginInsertRows(QModelIndex(), rowCount(), rowCount());
  177. m_fileListKeys.push_back(key);
  178. endInsertRows();
  179. }
  180. bool AssetBundlerAbstractFileTableModel::RemoveFileKey(const QModelIndex& index)
  181. {
  182. AZStd::string key = GetFileKey(index);
  183. if (key.empty())
  184. {
  185. // Error has already been thrown
  186. return false;
  187. }
  188. int row = index.row();
  189. beginRemoveRows(QModelIndex(), row, row);
  190. m_fileListKeys.erase(m_fileListKeys.begin() + row);
  191. m_keysWithUnsavedChanges.erase(key);
  192. endRemoveRows();
  193. return true;
  194. }
  195. bool AssetBundlerAbstractFileTableModel::DeleteFileByKey(const AZStd::string& key)
  196. {
  197. int indexRow = GetIndexRowByKey(key);
  198. if (indexRow >= 0)
  199. {
  200. return DeleteFile(index(indexRow, 0));
  201. }
  202. return false;
  203. }
  204. } // namespace AssetBundler