SourceAssetDetailsPanel.cpp 18 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415
  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 "SourceAssetDetailsPanel.h"
  9. #include "AssetTreeFilterModel.h"
  10. #include "GoToButton.h"
  11. #include "SourceAssetTreeItemData.h"
  12. #include "SourceAssetTreeModel.h"
  13. #include <AssetBuilderSDK/AssetBuilderSDK.h>
  14. #include <native/ui/GoToButtonDelegate.h>
  15. #include <native/ui/ui_GoToButton.h>
  16. #include <native/ui/ui_SourceAssetDetailsPanel.h>
  17. #include <native/utilities/assetUtils.h>
  18. #include <native/utilities/IPathConversion.h>
  19. #include <utilities/UuidManager.h>
  20. namespace AssetProcessor
  21. {
  22. SourceAssetDetailsPanel::SourceAssetDetailsPanel(QWidget* parent)
  23. : AssetDetailsPanel(parent)
  24. , m_ui(new Ui::SourceAssetDetailsPanel)
  25. {
  26. m_ui->setupUi(this);
  27. m_ui->scrollAreaWidgetContents->setLayout(m_ui->scrollableVerticalLayout);
  28. ResetText();
  29. auto* productsDelegate = new GoToButtonDelegate(this);
  30. connect(
  31. productsDelegate,
  32. &GoToButtonDelegate::Clicked,
  33. [this](const GoToButtonData& buttonData)
  34. {
  35. GoToProduct(buttonData.m_destination);
  36. });
  37. m_ui->productTable->setItemDelegate(productsDelegate);
  38. auto* intermediatesDelegate = new GoToButtonDelegate(this);
  39. connect(
  40. intermediatesDelegate,
  41. &GoToButtonDelegate::Clicked,
  42. [this](const GoToButtonData& buttonData)
  43. {
  44. GoToSource(buttonData.m_destination);
  45. });
  46. m_ui->IntermediateAssetsTable->setItemDelegate(intermediatesDelegate);
  47. auto* outgoingDependenciesDelegate = new GoToButtonDelegate(this);
  48. connect(
  49. outgoingDependenciesDelegate,
  50. &GoToButtonDelegate::Clicked,
  51. [this](const GoToButtonData& buttonData)
  52. {
  53. GoToSource(buttonData.m_destination);
  54. });
  55. m_ui->outgoingSourceDependenciesTable->setItemDelegate(outgoingDependenciesDelegate);
  56. auto* incomingDependenciesDelegate = new GoToButtonDelegate(this);
  57. connect(
  58. incomingDependenciesDelegate,
  59. &GoToButtonDelegate::Clicked,
  60. [this](const GoToButtonData& buttonData)
  61. {
  62. GoToSource(buttonData.m_destination);
  63. });
  64. m_ui->incomingSourceDependenciesTable->setItemDelegate(incomingDependenciesDelegate);
  65. }
  66. SourceAssetDetailsPanel::~SourceAssetDetailsPanel()
  67. {
  68. }
  69. void SourceAssetDetailsPanel::AssetDataSelectionChanged(const QItemSelection& selected, const QItemSelection& /*deselected*/)
  70. {
  71. AssetTreeFilterModel* filterModel = m_isIntermediateAsset ? m_intermediateFilterModel : m_sourceFilterModel;
  72. QItemSelection sourceSelection = filterModel->mapSelectionToSource(selected);
  73. // Even if multi-select is enabled, only display the first selected item.
  74. if (sourceSelection.indexes().count() == 0 || !sourceSelection.indexes()[0].isValid())
  75. {
  76. ResetText();
  77. return;
  78. }
  79. QModelIndex sourceModelIndex = sourceSelection.indexes()[0];
  80. if (!sourceModelIndex.isValid())
  81. {
  82. return;
  83. }
  84. AssetTreeItem* childItem = static_cast<AssetTreeItem*>(sourceModelIndex.internalPointer());
  85. const AZStd::shared_ptr<const SourceAssetTreeItemData> sourceItemData =
  86. AZStd::rtti_pointer_cast<const SourceAssetTreeItemData>(childItem->GetData());
  87. m_ui->assetNameLabel->setText(childItem->GetData()->m_name);
  88. if (childItem->GetData()->m_isFolder || !sourceItemData)
  89. {
  90. // Folders don't have details.
  91. SetDetailsVisible(false);
  92. return;
  93. }
  94. SetDetailsVisible(true);
  95. AssetDatabaseConnection assetDatabaseConnection;
  96. assetDatabaseConnection.OpenDatabase();
  97. if (m_isIntermediateAsset)
  98. {
  99. // First, find the product version of this intermediate asset.
  100. AZStd::string intermediateProductPath = AssetUtilities::GetIntermediateAssetDatabaseName(sourceItemData->m_assetDbName.c_str());
  101. AzToolsFramework::AssetDatabase::SourceDatabaseEntry upstreamSource;
  102. assetDatabaseConnection.QueryProductByProductName(
  103. intermediateProductPath.c_str(),
  104. [&](AzToolsFramework::AssetDatabase::ProductDatabaseEntry& productEntry)
  105. {
  106. // Second, get the source that created this product.
  107. assetDatabaseConnection.QuerySourceByProductID(
  108. productEntry.m_productID,
  109. [&](AzToolsFramework::AssetDatabase::SourceDatabaseEntry& sourceEntry)
  110. {
  111. upstreamSource = sourceEntry;
  112. return true;
  113. });
  114. return true;
  115. });
  116. // Finally, populate the UI with the information on the source that output this.
  117. m_ui->gotoAssetButton->m_ui->goToPushButton->disconnect();
  118. connect(
  119. m_ui->gotoAssetButton->m_ui->goToPushButton,
  120. &QPushButton::clicked,
  121. [=]
  122. {
  123. GoToSource(SourceAssetReference(upstreamSource).AbsolutePath().c_str());
  124. });
  125. m_ui->sourceAssetValueLabel->setText(upstreamSource.m_sourceName.c_str());
  126. }
  127. m_ui->scanFolderValueLabel->setText(sourceItemData->m_scanFolderInfo.m_scanFolder.c_str());
  128. m_ui->sourceGuidValueLabel->setText(sourceItemData->m_sourceInfo.m_sourceGuid.ToString<AZStd::string>().c_str());
  129. BuildProducts(assetDatabaseConnection, sourceItemData);
  130. BuildOutgoingSourceDependencies(assetDatabaseConnection, sourceItemData);
  131. BuildIncomingSourceDependencies(assetDatabaseConnection, sourceItemData);
  132. }
  133. void SourceAssetDetailsPanel::BuildProducts(
  134. AssetDatabaseConnection& assetDatabaseConnection, const AZStd::shared_ptr<const SourceAssetTreeItemData> sourceItemData)
  135. {
  136. // Clear & ClearContents leave the table dimensions the same, so set rowCount to zero to reset it.
  137. m_ui->productTable->setRowCount(0);
  138. m_ui->IntermediateAssetsTable->setRowCount(0);
  139. int intermediateAssetCount = 0;
  140. int productCount = 0;
  141. assetDatabaseConnection.QueryProductBySourceID(
  142. sourceItemData->m_sourceInfo.m_sourceID,
  143. [&](AzToolsFramework::AssetDatabase::ProductDatabaseEntry& productEntry)
  144. {
  145. AZ::s64 sourcePK;
  146. assetDatabaseConnection.QueryJobByProductID(
  147. productEntry.m_productID,
  148. [&sourcePK](AzToolsFramework::AssetDatabase::JobDatabaseEntry& jobEntry)
  149. {
  150. sourcePK = jobEntry.m_sourcePK;
  151. return true;
  152. });
  153. if (IsProductOutputFlagSet(productEntry, AssetBuilderSDK::ProductOutputFlags::IntermediateAsset))
  154. {
  155. m_ui->IntermediateAssetsTable->insertRow(intermediateAssetCount);
  156. AZStd::string intermediateAssetSourcePath;
  157. assetDatabaseConnection.QuerySourceBySourceID(
  158. sourcePK,
  159. [&intermediateAssetSourcePath](AzToolsFramework::AssetDatabase::SourceDatabaseEntry& sourceEntry)
  160. {
  161. intermediateAssetSourcePath = sourceEntry.m_sourceName;
  162. return true;
  163. });
  164. auto productPath = AssetUtilities::ProductPath::FromDatabasePath(productEntry.m_productName);
  165. auto* goToWidget = new QTableWidgetItem();
  166. goToWidget->setData(0, QVariant::fromValue(GoToButtonData{ productPath.GetIntermediatePath() }));
  167. QTableWidgetItem* rowName = new QTableWidgetItem(productEntry.m_productName.c_str());
  168. if (IsProductOutputFlagSet(productEntry, AssetBuilderSDK::ProductOutputFlags::CachedAsset))
  169. {
  170. rowName->setIcon(QIcon(":/cached_asset_item.png"));
  171. }
  172. m_ui->IntermediateAssetsTable->setItem(intermediateAssetCount, 0, goToWidget);
  173. m_ui->IntermediateAssetsTable->setItem(intermediateAssetCount, 1, rowName);
  174. ++intermediateAssetCount;
  175. }
  176. else
  177. {
  178. m_ui->productTable->insertRow(productCount);
  179. QTableWidgetItem* goToWidget = new QTableWidgetItem();
  180. goToWidget->setData(0, QVariant::fromValue(GoToButtonData{ productEntry.m_productName }));
  181. QTableWidgetItem* rowName = new QTableWidgetItem(productEntry.m_productName.c_str());
  182. if (IsProductOutputFlagSet(productEntry, AssetBuilderSDK::ProductOutputFlags::CachedAsset))
  183. {
  184. rowName->setIcon(QIcon(":/cached_asset_item.png"));
  185. }
  186. m_ui->productTable->setItem(productCount, 0, goToWidget);
  187. m_ui->productTable->setItem(productCount, 1, rowName);
  188. ++productCount;
  189. }
  190. return true;
  191. });
  192. m_ui->SourceAssetDetailTabs->setTabText(0, tr("Products (%1)").arg(productCount));
  193. m_ui->SourceAssetDetailTabs->setTabVisible(0, productCount > 0);
  194. m_ui->SourceAssetDetailTabs->setTabText(3, tr("Intermediate Assets (%1)").arg(intermediateAssetCount));
  195. m_ui->SourceAssetDetailTabs->setTabVisible(3, intermediateAssetCount > 0);
  196. }
  197. void SourceAssetDetailsPanel::BuildOutgoingSourceDependencies(
  198. AssetDatabaseConnection& assetDatabaseConnection, const AZStd::shared_ptr<const SourceAssetTreeItemData> sourceItemData)
  199. {
  200. m_ui->outgoingSourceDependenciesTable->setRowCount(0);
  201. int sourceDependencyCount = 0;
  202. assetDatabaseConnection.QueryDependsOnSourceBySourceDependency(
  203. sourceItemData->m_sourceInfo.m_sourceGuid,
  204. AzToolsFramework::AssetDatabase::SourceFileDependencyEntry::DEP_Any,
  205. [&](AzToolsFramework::AssetDatabase::SourceFileDependencyEntry& sourceFileDependencyEntry)
  206. {
  207. m_ui->outgoingSourceDependenciesTable->insertRow(sourceDependencyCount);
  208. // Some outgoing source dependencies are wildcard, or unresolved paths.
  209. // Only add a button to link to rows that actually exist.
  210. AzToolsFramework::AssetDatabase::SourceDatabaseEntry dependencyDetails;
  211. AZStd::string displayString;
  212. if (sourceFileDependencyEntry.m_dependsOnSource.IsUuid())
  213. {
  214. assetDatabaseConnection.QuerySourceBySourceGuid(
  215. sourceFileDependencyEntry.m_dependsOnSource.GetUuid(),
  216. [&](AzToolsFramework::AssetDatabase::SourceDatabaseEntry& entry)
  217. {
  218. dependencyDetails = entry;
  219. displayString = dependencyDetails.m_sourceName;
  220. return false;
  221. });
  222. if (displayString.empty())
  223. {
  224. displayString = sourceFileDependencyEntry.m_dependsOnSource.GetUuid().ToFixedString();
  225. }
  226. }
  227. else
  228. {
  229. AZStd::string queryString;
  230. if (AZ::IO::PathView(sourceFileDependencyEntry.m_dependsOnSource.GetPath().c_str()).IsAbsolute())
  231. {
  232. SourceAssetReference sourceAsset(sourceFileDependencyEntry.m_dependsOnSource.GetPath().c_str());
  233. AzToolsFramework::AssetDatabase::SourceDatabaseEntry sourceEntry;
  234. if (assetDatabaseConnection.GetSourceBySourceNameScanFolderId(
  235. sourceAsset.RelativePath().c_str(), sourceAsset.ScanFolderId(), sourceEntry))
  236. {
  237. dependencyDetails = sourceEntry;
  238. displayString = dependencyDetails.m_sourceName;
  239. }
  240. }
  241. else
  242. {
  243. AzToolsFramework::AssetDatabase::SourceDatabaseEntryContainer sources;
  244. if (assetDatabaseConnection.GetSourcesBySourceName(
  245. sourceFileDependencyEntry.m_dependsOnSource.GetPath().c_str(),
  246. sources))
  247. {
  248. // There may be multiple sources with the same relative path
  249. // Pick the one in the lowest ID scanfolder, which should correspond to the highest priority folder
  250. AZ::s64 lowestScanfolder = sources[0].m_scanFolderPK;
  251. for (const auto& source : sources)
  252. {
  253. if (source.m_scanFolderPK > lowestScanfolder)
  254. {
  255. lowestScanfolder = source.m_scanFolderPK;
  256. dependencyDetails = source;
  257. }
  258. }
  259. displayString = dependencyDetails.m_sourceName;
  260. }
  261. }
  262. if (displayString.empty())
  263. {
  264. displayString = sourceFileDependencyEntry.m_dependsOnSource.GetPath();
  265. }
  266. }
  267. IPathConversion* pathConversion = AZ::Interface<IPathConversion>::Get();
  268. AZ_Assert(pathConversion, "IPathConversion interface is not available");
  269. SourceAssetTreeModel* treeModel = dependencyDetails.m_scanFolderPK == pathConversion->GetIntermediateAssetScanFolderId()
  270. ? m_intermediateTreeModel : m_sourceTreeModel;
  271. QModelIndex goToIndex = treeModel->GetIndexForSource(dependencyDetails.m_sourceName, dependencyDetails.m_scanFolderPK);
  272. if (goToIndex.isValid())
  273. {
  274. auto* goToWidget = new QTableWidgetItem();
  275. goToWidget->setData(
  276. 0, QVariant::fromValue(GoToButtonData{ SourceAssetReference(dependencyDetails).AbsolutePath().String() }));
  277. m_ui->outgoingSourceDependenciesTable->setItem(sourceDependencyCount, 0, goToWidget);
  278. }
  279. QTableWidgetItem* rowName = new QTableWidgetItem(displayString.c_str());
  280. m_ui->outgoingSourceDependenciesTable->setItem(sourceDependencyCount, 1, rowName);
  281. ++sourceDependencyCount;
  282. return true;
  283. });
  284. m_ui->SourceAssetDetailTabs->setTabText(1, tr("Dependencies - Out (%1)").arg(sourceDependencyCount));
  285. m_ui->SourceAssetDetailTabs->setTabVisible(1, sourceDependencyCount > 0);
  286. }
  287. void SourceAssetDetailsPanel::BuildIncomingSourceDependencies(
  288. AssetDatabaseConnection& assetDatabaseConnection, const AZStd::shared_ptr<const SourceAssetTreeItemData> sourceItemData)
  289. {
  290. m_ui->incomingSourceDependenciesTable->setRowCount(0);
  291. int sourceDependencyCount = 0;
  292. auto absolutePath = AZ::IO::Path(sourceItemData->m_scanFolderInfo.m_scanFolder) / sourceItemData->m_sourceInfo.m_sourceName;
  293. assetDatabaseConnection.QuerySourceDependencyByDependsOnSource(
  294. sourceItemData->m_sourceInfo.m_sourceGuid,
  295. sourceItemData->m_sourceInfo.m_sourceName.c_str(),
  296. absolutePath.FixedMaxPathStringAsPosix().c_str(),
  297. AzToolsFramework::AssetDatabase::SourceFileDependencyEntry::DEP_Any,
  298. [&](AzToolsFramework::AssetDatabase::SourceFileDependencyEntry& sourceFileDependencyEntry)
  299. {
  300. m_ui->incomingSourceDependenciesTable->insertRow(sourceDependencyCount);
  301. AZStd::string sourceName;
  302. AzToolsFramework::AssetDatabase::SourceDatabaseEntry sourceEntry;
  303. assetDatabaseConnection.QuerySourceBySourceGuid(
  304. sourceFileDependencyEntry.m_sourceGuid,
  305. [&sourceName, &sourceEntry](const auto& entry)
  306. {
  307. sourceEntry = entry;
  308. sourceName = entry.m_sourceName;
  309. return false;
  310. });
  311. if (sourceName.empty())
  312. {
  313. sourceName = AZStd::string::format("Invalid UUID - %s", sourceFileDependencyEntry.m_sourceGuid.ToFixedString().c_str());
  314. }
  315. auto* goToWidget = new QTableWidgetItem();
  316. goToWidget->setData(0, QVariant::fromValue(GoToButtonData{ SourceAssetReference(sourceEntry).AbsolutePath().String() }));
  317. m_ui->incomingSourceDependenciesTable->setItem(sourceDependencyCount, 0, goToWidget);
  318. QTableWidgetItem* rowName = new QTableWidgetItem(QString(sourceName.c_str()));
  319. m_ui->incomingSourceDependenciesTable->setItem(sourceDependencyCount, 1, rowName);
  320. ++sourceDependencyCount;
  321. return true;
  322. });
  323. m_ui->SourceAssetDetailTabs->setTabText(2, tr("Dependencies - In (%1)").arg(sourceDependencyCount));
  324. m_ui->SourceAssetDetailTabs->setTabVisible(2, sourceDependencyCount > 0);
  325. }
  326. void SourceAssetDetailsPanel::ResetText()
  327. {
  328. m_ui->assetNameLabel->setText(tr("Select an asset to see details"));
  329. SetDetailsVisible(false);
  330. }
  331. void SourceAssetDetailsPanel::SetDetailsVisible(bool visible)
  332. {
  333. // The folder selected description has opposite visibility from everything else.
  334. m_ui->folderSelectedDescription->setVisible(!visible);
  335. m_ui->scanFolderTitleLabel->setVisible(visible);
  336. m_ui->scanFolderValueLabel->setVisible(visible);
  337. m_ui->sourceGuidTitleLabel->setVisible(visible);
  338. m_ui->sourceGuidValueLabel->setVisible(visible);
  339. m_ui->sourceAssetTitleLabel->setVisible(visible && m_isIntermediateAsset);
  340. m_ui->gotoAssetButton->setVisible(visible && m_isIntermediateAsset);
  341. m_ui->sourceAssetValueLabel->setVisible(visible && m_isIntermediateAsset);
  342. m_ui->AssetInfoSeparatorLine->setVisible(visible);
  343. m_ui->SourceAssetDetailTabs->setVisible(visible);
  344. }
  345. } // namespace AssetProcessor