SeedListTableModel.cpp 12 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329
  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/SeedListTableModel.h>
  9. #include <source/utils/utils.h>
  10. #include <AzCore/Outcome/Outcome.h>
  11. #include <AzCore/std/smart_ptr/make_shared.h>
  12. #include <AzFramework/IO/LocalFileIO.h>
  13. #include <AzFramework/StringFunc/StringFunc.h>
  14. #include <AzToolsFramework/AssetCatalog/PlatformAddressedAssetCatalogManager.h>
  15. #include <QFont>
  16. namespace AssetBundler
  17. {
  18. //////////////////////////////////////////////////////////////////////////////////////////////////
  19. // AdditionalSeedInfo
  20. //////////////////////////////////////////////////////////////////////////////////////////////////
  21. AdditionalSeedInfo::AdditionalSeedInfo(const QString& relativePath, const QString& platformList)
  22. : m_relativePath(relativePath)
  23. , m_platformList(platformList)
  24. {
  25. }
  26. //////////////////////////////////////////////////////////////////////////////////////////////////
  27. // SeedListTableModel
  28. //////////////////////////////////////////////////////////////////////////////////////////////////
  29. SeedListTableModel::SeedListTableModel(
  30. QObject* parent,
  31. const AZStd::string& absolutePath,
  32. const AZStd::vector<AZStd::string>& defaultSeeds,
  33. const AzFramework::PlatformFlags& platforms)
  34. : QAbstractTableModel(parent)
  35. , m_errorImage(QStringLiteral(":/stylesheet/img/logging/error.svg"))
  36. {
  37. m_seedListManager.reset(new AzToolsFramework::AssetSeedManager());
  38. if (absolutePath.empty() && defaultSeeds.empty())
  39. {
  40. return;
  41. }
  42. if (!defaultSeeds.empty())
  43. {
  44. for (const AZStd::string& seed : defaultSeeds)
  45. {
  46. m_seedListManager->AddSeedAssetForValidPlatforms(seed, platforms);
  47. }
  48. m_isFileOnDisk = false;
  49. }
  50. else
  51. {
  52. m_seedListManager->Load(absolutePath);
  53. }
  54. AZ::Data::AssetInfo assetInfo;
  55. QString platformList;
  56. const auto& enabledPlatforms = AzToolsFramework::PlatformAddressedAssetCatalogManager::GetEnabledPlatforms();
  57. [[maybe_unused]] const bool hasEnabledPlatforms = !enabledPlatforms.empty();
  58. AZ_Error(AssetBundler::AppWindowName, hasEnabledPlatforms, "Unable to find any enabled asset platforms. Please verify the Asset Processor has run and generated assets successfully.");
  59. [[maybe_unused]] bool missingAssets = false;
  60. for (const auto& seed : m_seedListManager->GetAssetSeedList())
  61. {
  62. for (AZ::PlatformId platformId : enabledPlatforms)
  63. {
  64. if (AZ::PlatformHelper::HasPlatformFlag(seed.m_platformFlags, platformId))
  65. {
  66. assetInfo = AzToolsFramework::AssetSeedManager::GetAssetInfoById(
  67. seed.m_assetId,
  68. platformId,
  69. absolutePath,
  70. seed.m_assetRelativePath);
  71. if (assetInfo.m_assetId.IsValid())
  72. {
  73. break;
  74. }
  75. }
  76. }
  77. platformList = QString(m_seedListManager->GetReadablePlatformList(seed).c_str());
  78. m_additionalSeedInfoMap[seed.m_assetId].reset(new AdditionalSeedInfo(assetInfo.m_relativePath.c_str(), platformList));
  79. // Missing assets still show up in the seed list view. Display An error message where the blank filename would otherwise be.
  80. if (!assetInfo.m_assetId.IsValid())
  81. {
  82. const AZStd::string assetIdStr(seed.m_assetId.ToString<AZStd::string>());
  83. m_additionalSeedInfoMap[seed.m_assetId]->m_errorMessage = tr("Asset not found for enabled platforms: path hint '%1', asset ID '%2'").arg(seed.m_assetRelativePath.c_str()).arg(assetIdStr.c_str());
  84. missingAssets = true;
  85. }
  86. }
  87. AZ_Warning(AssetBundler::AppWindowName, !missingAssets, "Not all assets were found. Please verify the Asset Processor has run for the enabled platforms and generated assets successfully.");
  88. }
  89. AZ::Outcome<AzFramework::PlatformFlags, void> SeedListTableModel::GetSeedPlatforms(const QModelIndex& index) const
  90. {
  91. auto seedOutcome = GetSeedInfo(index);
  92. if (!seedOutcome.IsSuccess())
  93. {
  94. // Error has already been thrown
  95. return AZ::Failure();
  96. }
  97. return AZ::Success(seedOutcome.GetValue().get().m_platformFlags);
  98. }
  99. bool SeedListTableModel::Save(const AZStd::string& absolutePath)
  100. {
  101. if (!HasUnsavedChanges())
  102. {
  103. // There are no changes, so there is nothing to save
  104. return true;
  105. }
  106. SetHasUnsavedChanges(!m_seedListManager->Save(absolutePath));
  107. return !HasUnsavedChanges();
  108. }
  109. bool SeedListTableModel::SetSeedPlatforms(const QModelIndex& index, const AzFramework::PlatformFlags& platforms)
  110. {
  111. auto seedOutcome = GetSeedInfo(index);
  112. if (!seedOutcome.IsSuccess())
  113. {
  114. // Error has already been thrown
  115. return false;
  116. }
  117. if (platforms == AzFramework::PlatformFlags::Platform_NONE)
  118. {
  119. AZ_Error(AssetBundler::AppWindowName, false, "Cannot Edit Platforms: No platforms were selected");
  120. return false;
  121. }
  122. auto setPlatformOutcome = m_seedListManager->SetSeedPlatformFlags(index.row(), platforms);
  123. if (!setPlatformOutcome.IsSuccess())
  124. {
  125. AZ_Error(AssetBundler::AppWindowName, false, setPlatformOutcome.GetError().c_str());
  126. return false;
  127. }
  128. // Update the cached display info
  129. auto additionalSeedInfo = m_additionalSeedInfoMap.find(seedOutcome.GetValue().get().m_assetId);
  130. if (additionalSeedInfo == m_additionalSeedInfoMap.end())
  131. {
  132. AZ_Error(AssetBundler::AppWindowName, false, "Unable to find additional Seed info");
  133. return false;
  134. }
  135. auto visiblePlatforms = platforms;
  136. #ifndef AZ_TOOLS_EXPAND_FOR_RESTRICTED_PLATFORMS
  137. // don't include restricted platforms when they are not enabled
  138. visiblePlatforms &= AzFramework::PlatformFlags::UnrestrictedPlatforms;
  139. #endif
  140. additionalSeedInfo->second->m_platformList =
  141. QString(AzFramework::PlatformHelper::GetCommaSeparatedPlatformList(visiblePlatforms).c_str());
  142. SetHasUnsavedChanges(true);
  143. // Update the display
  144. QModelIndex firstChangedIndex = QAbstractTableModel::index(index.row(), Column::ColumnRelativePath);
  145. QModelIndex lastChangedIndex = QAbstractTableModel::index(index.row(), Column::Max - 1);
  146. emit dataChanged(firstChangedIndex, lastChangedIndex, { Qt::DisplayRole });
  147. return true;
  148. }
  149. bool SeedListTableModel::AddSeed(const AZStd::string& seedRelativePath, const AzFramework::PlatformFlags& platforms)
  150. {
  151. AZStd::pair<AZ::Data::AssetId, AzFramework::PlatformFlags> addSeedsResult =
  152. m_seedListManager->AddSeedAssetForValidPlatforms(seedRelativePath, platforms);
  153. AzFramework::PlatformFlags validPlatforms = addSeedsResult.second;
  154. if (!addSeedsResult.first.IsValid() || validPlatforms == AzFramework::PlatformFlags::Platform_NONE)
  155. {
  156. // Error has already been thrown
  157. return false;
  158. }
  159. #ifndef AZ_TOOLS_EXPAND_FOR_RESTRICTED_PLATFORMS
  160. // don't include restricted platforms when they are not enabled
  161. validPlatforms &= AzFramework::PlatformFlags::UnrestrictedPlatforms;
  162. #endif
  163. QString platformList = QString(AzFramework::PlatformHelper::GetCommaSeparatedPlatformList(validPlatforms).c_str());
  164. int lastRowIndex = AZStd::max(rowCount() - 1, 0);
  165. beginInsertRows(QModelIndex(), lastRowIndex, lastRowIndex);
  166. m_additionalSeedInfoMap[addSeedsResult.first].reset(new AdditionalSeedInfo(QString(seedRelativePath.c_str()), platformList));
  167. endInsertRows();
  168. SetHasUnsavedChanges(true);
  169. return true;
  170. }
  171. bool SeedListTableModel::RemoveSeed(const QModelIndex& seedIndex)
  172. {
  173. auto seedOutcome = GetSeedInfo(seedIndex);
  174. if (!seedOutcome.IsSuccess())
  175. {
  176. // Error has already been thrown
  177. return false;
  178. }
  179. int row = seedIndex.row();
  180. beginRemoveRows(QModelIndex(), row, row);
  181. m_seedListManager->RemoveSeedAsset(seedOutcome.GetValue().get().m_assetId, seedOutcome.GetValue().get().m_platformFlags);
  182. m_additionalSeedInfoMap.erase(seedOutcome.GetValue().get().m_assetId);
  183. endRemoveRows();
  184. SetHasUnsavedChanges(true);
  185. return true;
  186. }
  187. int SeedListTableModel::rowCount(const QModelIndex& parent) const
  188. {
  189. return parent.isValid() ? 0 : static_cast<int>(m_additionalSeedInfoMap.size());
  190. }
  191. int SeedListTableModel::columnCount(const QModelIndex& parent) const
  192. {
  193. return parent.isValid() ? 0 : Column::Max;
  194. }
  195. QVariant SeedListTableModel::headerData(int section, Qt::Orientation orientation, int role) const
  196. {
  197. if (role == Qt::DisplayRole && orientation == Qt::Horizontal)
  198. {
  199. switch (section)
  200. {
  201. case Column::ColumnRelativePath:
  202. return QString("Seed");
  203. case Column::ColumnPlatformList:
  204. return QString("Platforms");
  205. default:
  206. break;
  207. }
  208. }
  209. return QVariant();
  210. }
  211. QVariant SeedListTableModel::data(const QModelIndex& index, int role) const
  212. {
  213. auto additionalSeedInfoOutcome = GetAdditionalSeedInfo(index);
  214. if (!additionalSeedInfoOutcome.IsSuccess())
  215. {
  216. return QVariant();
  217. }
  218. switch (role)
  219. {
  220. case Qt::DecorationRole:
  221. if (index.column() == Column::ColumnRelativePath)
  222. {
  223. if (!additionalSeedInfoOutcome.GetValue()->m_errorMessage.isEmpty())
  224. {
  225. return m_errorImage;
  226. }
  227. }
  228. break;
  229. case Qt::DisplayRole:
  230. {
  231. if (index.column() == Column::ColumnRelativePath)
  232. {
  233. // If this seed has an error, display that instead of the path.
  234. if (!additionalSeedInfoOutcome.GetValue()->m_errorMessage.isEmpty())
  235. {
  236. return additionalSeedInfoOutcome.GetValue()->m_errorMessage;
  237. }
  238. return additionalSeedInfoOutcome.GetValue()->m_relativePath;
  239. }
  240. else if (index.column() == Column::ColumnPlatformList)
  241. {
  242. return additionalSeedInfoOutcome.GetValue()->m_platformList;
  243. }
  244. }
  245. default:
  246. break;
  247. }
  248. return QVariant();
  249. }
  250. AZ::Outcome<AZStd::reference_wrapper<const AzFramework::SeedInfo>, void> SeedListTableModel::GetSeedInfo(const QModelIndex& index) const
  251. {
  252. int row = index.row();
  253. int col = index.column();
  254. if (row >= rowCount() || row < 0 || col >= columnCount() || col < 0)
  255. {
  256. AZ_Error(AssetBundler::AppWindowName, false, "Selected index (%i, %i) is out of range", row, col);
  257. return AZ::Failure();
  258. }
  259. return m_seedListManager->GetAssetSeedList().at(row);
  260. }
  261. AZ::Outcome<AdditionalSeedInfoPtr, void> SeedListTableModel::GetAdditionalSeedInfo(const QModelIndex& index) const
  262. {
  263. auto seedInfoOutcome = GetSeedInfo(index);
  264. if (!seedInfoOutcome.IsSuccess())
  265. {
  266. // Error has already been thrown
  267. return AZ::Failure();
  268. }
  269. auto additionalSeedInfoIt = m_additionalSeedInfoMap.find(seedInfoOutcome.GetValue().get().m_assetId);
  270. if (additionalSeedInfoIt == m_additionalSeedInfoMap.end())
  271. {
  272. return AZ::Failure();
  273. }
  274. return AZ::Success(additionalSeedInfoIt->second);
  275. }
  276. } // namespace AssetBundler