/* * All or portions of this file Copyright (c) Amazon.com, Inc. or its affiliates or * its licensors. * * For complete copyright and license terms please see the LICENSE at the root of this * distribution (the "License"). All use of this software is governed by the License, * or, if provided, by the license below or the license accompanying this file. Do not * remove or modify any license notices. This file is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * */ #include #include #include #include #include #include #include #include #include namespace { ScriptCanvasEditor::NodePaletteNodeUsageRootItem* ExternalCreatePaletteRoot(const ScriptCanvasEditor::NodePaletteModel& nodePaletteModel, AZStd::unordered_map< ScriptCanvas::NodeTypeIdentifier, GraphCanvas::GraphCanvasTreeItem* >& leafMap) { ScriptCanvasEditor::NodePaletteNodeUsageRootItem* root = aznew ScriptCanvasEditor::NodePaletteNodeUsageRootItem(nodePaletteModel); const ScriptCanvasEditor::NodePaletteModel::NodePaletteRegistry& nodeRegistry = nodePaletteModel.GetNodeRegistry(); for (const auto& registryPair : nodeRegistry) { const ScriptCanvasEditor::NodePaletteModelInformation* modelInformation = registryPair.second; GraphCanvas::GraphCanvasTreeItem* parentItem = root->GetCategoryNode(modelInformation->m_categoryPath.c_str()); GraphCanvas::NodePaletteTreeItem* createdItem = nullptr; createdItem = parentItem->CreateChildNode(modelInformation->m_nodeIdentifier, modelInformation->m_displayName); if (createdItem) { modelInformation->PopulateTreeItem((*createdItem)); leafMap[modelInformation->m_nodeIdentifier] = createdItem; } } root->PruneEmptyNodes(); return root; } } namespace ScriptCanvasEditor { ////////////////////////////////////////// // ScriptCanvasAssetNodeUsageFilterModel ////////////////////////////////////////// ScriptCanvasAssetNodeUsageFilterModel::ScriptCanvasAssetNodeUsageFilterModel() : m_nodeIdentifier(0) { } bool ScriptCanvasAssetNodeUsageFilterModel::filterAcceptsRow(int sourceRow, const QModelIndex& sourceParent) const { // Never want to show something if we don't have a node type identifier if (m_nodeIdentifier == 0) { return false; } QAbstractItemModel* model = sourceModel(); QModelIndex index = model->index(sourceRow, 0, sourceParent); ScriptCanvasAssetNodeUsageTreeItem* treeItem = static_cast(index.internalPointer()); if (!treeItem->GetAssetId().IsValid()) { for (int i = 0; i < treeItem->GetChildCount(); ++i) { if (filterAcceptsRow(i, index)) { return true; } } } else { treeItem->SetActiveNodeType(m_nodeIdentifier); if (treeItem->GetNodeCount() == 0) { return false; } bool showRow = m_filter.isEmpty(); if (!showRow) { const QString& name = treeItem->GetName(); int regexIndex = name.lastIndexOf(m_regex); showRow = regexIndex >= 0; if (!showRow) { ScriptCanvasAssetNodeUsageTreeItem* parentItem = static_cast(treeItem->GetParent()); while (!showRow && parentItem) { ScriptCanvasAssetNodeUsageTreeItem* nextItem = static_cast(parentItem->GetParent()); // This means we are the root element. And we don't want to match based on it. if (nextItem == nullptr) { break; } const QString& parentName = parentItem->GetName(); int regexIndex = parentName.lastIndexOf(m_regex); if (regexIndex >= 0) { showRow = true; } parentItem = nextItem; } } } return showRow; } return false; } void ScriptCanvasAssetNodeUsageFilterModel::SetFilter(const QString& filterName) { m_filter = filterName; m_regex = QRegExp(m_filter, Qt::CaseInsensitive); invalidate(); } void ScriptCanvasAssetNodeUsageFilterModel::SetNodeTypeFilter(const ScriptCanvas::NodeTypeIdentifier& nodeType) { m_nodeIdentifier = nodeType; invalidate(); } ///////////////////// // StatisticsDialog ///////////////////// StatisticsDialog::StatisticsDialog(const NodePaletteModel& nodePaletteModel, AzToolsFramework::AssetBrowser::AssetBrowserFilterModel* scriptCanvasAssetBrowserModel, QWidget* widget) : QDialog(widget) , m_nodePaletteModel(nodePaletteModel) , m_ui(new Ui::ScriptCanvasStatisticsDialog()) , m_treeRoot(nullptr) , m_scriptCanvasAssetBrowserModel(scriptCanvasAssetBrowserModel) , m_scriptCanvasAssetTreeRoot(nullptr) , m_scriptCanvasAssetTree(nullptr) , m_scriptCanvasAssetFilterModel(nullptr) { setWindowFlags(Qt::WindowFlags::enum_type::WindowCloseButtonHint); m_ui->setupUi(this); AzQtComponents::StyleManager::setStyleSheet(this, QStringLiteral("style:Editor.qss")); } StatisticsDialog::~StatisticsDialog() { AzFramework::AssetCatalogEventBus::Handler::BusDisconnect(); } void StatisticsDialog::OnCatalogAssetChanged(const AZ::Data::AssetId& assetId) { if (m_scriptCanvasAssetTreeRoot) { AZ::Data::AssetInfo assetInfo; AZ::Data::AssetCatalogRequestBus::BroadcastResult(assetInfo, &AZ::Data::AssetCatalogRequests::GetAssetInfoById, assetId); if (assetInfo.m_assetId.IsValid()) { if (assetInfo.m_assetType == azrtti_typeid() || assetInfo.m_assetType == azrtti_typeid()) { m_scriptCanvasAssetTreeRoot->RegisterAsset(assetId, assetInfo.m_assetType); } } } } void StatisticsDialog::OnCatalogAssetAdded(const AZ::Data::AssetId& assetId) { OnCatalogAssetChanged(assetId); } void StatisticsDialog::OnCatalogAssetRemoved(const AZ::Data::AssetId& assetId, const AZ::Data::AssetInfo& /*assetInfo*/) { // at this point, the asset is gone. You can't search for it in the catalog. if (m_scriptCanvasAssetTreeRoot) { m_scriptCanvasAssetTreeRoot->RemoveAsset(assetId); } } void StatisticsDialog::OnAssetModelRepopulated() { ResetModel(); } void StatisticsDialog::OnAssetNodeAdded(NodePaletteModelInformation* modelInformation) { auto leafIter = m_leafMap.find(modelInformation->m_nodeIdentifier); if (leafIter != m_leafMap.end()) { // Duplicate Id. Ignore for now. return; } GraphCanvas::GraphCanvasTreeItem* parentItem = m_treeRoot->GetCategoryNode(modelInformation->m_categoryPath.c_str()); GraphCanvas::NodePaletteTreeItem* createdItem = nullptr; createdItem = parentItem->CreateChildNode(modelInformation->m_nodeIdentifier, modelInformation->m_displayName); if (createdItem) { modelInformation->PopulateTreeItem((*createdItem)); m_leafMap[modelInformation->m_nodeIdentifier] = createdItem; } else { m_treeRoot->PruneEmptyNodes(); } } void StatisticsDialog::OnAssetNodeRemoved(NodePaletteModelInformation* modelInformation) { auto leafIter = m_leafMap.find(modelInformation->m_nodeIdentifier); if (leafIter != m_leafMap.end()) { leafIter->second->DetachItem(); delete leafIter->second; m_leafMap.erase(leafIter); m_treeRoot->PruneEmptyNodes(); } } void StatisticsDialog::OnScriptCanvasAssetClicked(const QModelIndex& index) { if (index.isValid()) { if (index.column() == ScriptCanvasAssetNodeUsageTreeItem::Column::OpenIcon) { QModelIndex sourceIndex = m_scriptCanvasAssetFilterModel->mapToSource(index); ScriptCanvasAssetNodeUsageTreeItem* treeItem = static_cast(sourceIndex.internalPointer()); if (treeItem->GetAssetId().IsValid()) { GeneralRequestBus::Broadcast(&GeneralRequests::OpenScriptCanvasAssetId, treeItem->GetAssetId()); } } } } void StatisticsDialog::showEvent(QShowEvent* showEvent) { InitStatisticsWindow(); QDialog::showEvent(showEvent); } void StatisticsDialog::OnSelectionCleared() { m_scriptCanvasAssetFilterModel->SetNodeTypeFilter(0); m_ui->statDisplayName->setText("N/A"); m_ui->totalUsageCount->setText(QString::number(0)); m_ui->uniqueGraphsCount->setText(QString::number(0)); m_ui->averageGraphUsages->setText(QString::number(0)); } void StatisticsDialog::OnItemSelected(const GraphCanvas::GraphCanvasTreeItem* treeItem) { const NodePaletteNodeUsagePaletteItem* usageItem = azrtti_cast(treeItem); if (usageItem) { m_scriptCanvasAssetFilterModel->SetNodeTypeFilter(usageItem->GetNodeTypeIdentifier()); m_ui->scriptCanvasAssetTree->expandAll(); const ScriptCanvasAssetNodeUsageTreeItemRoot::ScriptCanvasAssetMap& assetMapping = m_scriptCanvasAssetTreeRoot->GetAssetTreeItems(); int totalNodeCount = 0; int uniqueGraphs = 0; for (auto itemPair : assetMapping) { int nodeCount = itemPair.second->GetNodeCount(); if (nodeCount > 0) { totalNodeCount += nodeCount; uniqueGraphs++; } } m_ui->statDisplayName->setText(usageItem->GetName()); m_ui->totalUsageCount->setText(QString::number(totalNodeCount)); m_ui->uniqueGraphsCount->setText(QString::number(uniqueGraphs)); float averageUses = 0; if (uniqueGraphs != 0) { averageUses = static_cast(totalNodeCount) / static_cast(uniqueGraphs); } m_ui->averageGraphUsages->setText(QString::number(averageUses, 'g', 2)); } else { OnSelectionCleared(); } } void StatisticsDialog::OnFilterUpdated(const QString& filterText) { m_scriptCanvasAssetFilterModel->SetFilter(filterText); m_ui->scriptCanvasAssetTree->expandAll(); } void StatisticsDialog::OnScriptCanvasAssetRowsInserted(QModelIndex parentIndex, int first, int last) { for (int i = first; i <= last; ++i) { QModelIndex modelIndex = m_scriptCanvasAssetBrowserModel->index(first, 0, parentIndex); QModelIndex sourceIndex = m_scriptCanvasAssetBrowserModel->mapToSource(modelIndex); const AzToolsFramework::AssetBrowser::AssetBrowserEntry* entry = reinterpret_cast(sourceIndex.internalPointer()); ProcessAsset(entry); } } void StatisticsDialog::InitStatisticsWindow() { if (m_treeRoot == nullptr) { m_treeRoot = ExternalCreatePaletteRoot(m_nodePaletteModel, m_leafMap); GraphCanvas::NodePaletteConfig paletteConfig; paletteConfig.m_rootTreeItem = m_treeRoot; paletteConfig.m_editorId = ScriptCanvasEditor::AssetEditorId; paletteConfig.m_mimeType = ""; paletteConfig.m_isInContextMenu = false; paletteConfig.m_saveIdentifier = "ScriptCanvas_UsageStatistics"; paletteConfig.m_clearSelectionOnSceneChange = false; paletteConfig.m_allowArrowKeyNavigation = true; m_ui->nodePaletteWidget->SetupNodePalette(paletteConfig); m_scriptCanvasAssetTreeRoot = aznew ScriptCanvasAssetNodeUsageTreeItemRoot(); m_scriptCanvasAssetTree = aznew GraphCanvas::GraphCanvasTreeModel(m_scriptCanvasAssetTreeRoot); m_scriptCanvasAssetFilterModel = aznew ScriptCanvasAssetNodeUsageFilterModel(); m_scriptCanvasAssetFilterModel->setSourceModel(m_scriptCanvasAssetTree); TraverseTree(); AzFramework::AssetCatalogEventBus::Handler::BusConnect(); m_ui->scriptCanvasAssetTree->setModel(m_scriptCanvasAssetFilterModel); m_ui->splitter->setStretchFactor(0, 1); m_ui->splitter->setStretchFactor(1, 2); m_ui->searchWidget->SetFilterInputInterval(AZStd::chrono::milliseconds(250)); m_ui->scriptCanvasAssetTree->header()->setSectionResizeMode(ScriptCanvasAssetNodeUsageTreeItem::Column::Name, QHeaderView::ResizeMode::ResizeToContents); m_ui->scriptCanvasAssetTree->header()->setSectionResizeMode(ScriptCanvasAssetNodeUsageTreeItem::Column::UsageCount, QHeaderView::ResizeMode::Fixed); m_ui->scriptCanvasAssetTree->header()->resizeSection(ScriptCanvasAssetNodeUsageTreeItem::Column::UsageCount, 30); QObject::connect(m_ui->scriptCanvasAssetTree, &QTreeView::clicked, this, &StatisticsDialog::OnScriptCanvasAssetClicked); QObject::connect(m_ui->nodePaletteWidget, &GraphCanvas::NodePaletteWidget::OnSelectionCleared, this, &StatisticsDialog::OnSelectionCleared); QObject::connect(m_ui->nodePaletteWidget, &GraphCanvas::NodePaletteWidget::OnTreeItemSelected, this, &StatisticsDialog::OnItemSelected); QObject::connect(m_ui->searchWidget, &AzQtComponents::FilteredSearchWidget::TextFilterChanged, this, &StatisticsDialog::OnFilterUpdated); QObject::connect(m_scriptCanvasAssetBrowserModel, &QAbstractItemModel::rowsInserted, this, &StatisticsDialog::OnScriptCanvasAssetRowsInserted); OnSelectionCleared(); NodePaletteModelNotificationBus::Handler::BusConnect(m_nodePaletteModel.GetNotificationId()); } } void StatisticsDialog::ResetModel() { if (m_treeRoot) { m_leafMap.clear(); m_treeRoot = ExternalCreatePaletteRoot(m_nodePaletteModel, m_leafMap); m_ui->nodePaletteWidget->ResetModel(m_treeRoot); } } void StatisticsDialog::TraverseTree(QModelIndex index) { QModelIndex sourceIndex = m_scriptCanvasAssetBrowserModel->mapToSource(index); AzToolsFramework::AssetBrowser::AssetBrowserEntry* entry = reinterpret_cast(sourceIndex.internalPointer()); ProcessAsset(entry); int rowCount = m_scriptCanvasAssetBrowserModel->rowCount(index); for (int i = 0; i < rowCount; ++i) { QModelIndex nextIndex = m_scriptCanvasAssetBrowserModel->index(i, 0, index); TraverseTree(nextIndex); } } void StatisticsDialog::ProcessAsset(const AzToolsFramework::AssetBrowser::AssetBrowserEntry* entry) { if (entry) { if (entry->GetEntryType() == AzToolsFramework::AssetBrowser::AssetBrowserEntry::AssetEntryType::Product) { const AzToolsFramework::AssetBrowser::ProductAssetBrowserEntry* productEntry = static_cast(entry); if (productEntry->GetAssetType() == azrtti_typeid() || productEntry->GetAssetType() == azrtti_typeid()) { const AZ::Data::AssetId& assetId = productEntry->GetAssetId(); m_scriptCanvasAssetTreeRoot->RegisterAsset(assetId, productEntry->GetAssetType()); } } } } #include }