| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593 |
- /*
- * Copyright (c) Contributors to the Open 3D Engine Project.
- * For complete copyright and license terms please see the LICENSE at the root of this distribution.
- *
- * SPDX-License-Identifier: Apache-2.0 OR MIT
- *
- */
- #include <QDateTime>
- #include <QDir>
- #include <QMessageBox>
- #include <QProcess>
- #include <QScrollBar>
- #include <QToolButton>
- #include <AzCore/Asset/AssetManagerBus.h>
- #include <AzCore/Component/ComponentApplicationBus.h>
- #include <AzCore/Component/TickBus.h>
- #include <AzCore/IO/SystemFile.h>
- #include <AzCore/UserSettings/UserSettingsProvider.h>
- #include <AzFramework/Asset/AssetSystemBus.h>
- #include <AzFramework/IO/FileOperations.h>
- #include <AzQtComponents/Components/Widgets/CheckBox.h>
- #include <AzQtComponents/Utilities/DesktopUtilities.h>
- #include <AzToolsFramework/API/EditorAssetSystemAPI.h>
- #include <AzToolsFramework/API/ToolsApplicationAPI.h>
- #include <AzToolsFramework/SourceControl/SourceControlAPI.h>
- #include <Editor/Settings.h>
- #include <Editor/View/Windows/Tools/UpgradeTool/Controller.h>
- #include <Editor/View/Windows/Tools/UpgradeTool/LogTraits.h>
- #include <Editor/View/Windows/Tools/UpgradeTool/ui_View.h>
- #include <ScriptCanvas/Bus/EditorScriptCanvasBus.h>
- #include <ScriptCanvas/Components/EditorGraph.h>
- namespace ScriptCanvasEditor
- {
- namespace VersionExplorer
- {
- Controller::Controller(QWidget* parent)
- : AzQtComponents::StyledDialog(parent)
- , m_view(new Ui::View())
- {
- m_view->setupUi(this);
- m_view->tableWidget->horizontalHeader()->setVisible(false);
- m_view->tableWidget->horizontalHeader()->setSectionResizeMode(0, QHeaderView::Stretch);
- m_view->tableWidget->horizontalHeader()->setSectionResizeMode(3, QHeaderView::Fixed);
- m_view->tableWidget->setColumnWidth(3, 22);
- m_view->textEdit->setHorizontalScrollBarPolicy(Qt::ScrollBarPolicy::ScrollBarAsNeeded);
- m_view->textEdit->setVerticalScrollBarPolicy(Qt::ScrollBarPolicy::ScrollBarAlwaysOn);
- connect(m_view->scanButton, &QPushButton::pressed, this, &Controller::OnButtonPressScan);
- connect(m_view->closeButton, &QPushButton::pressed, this, &Controller::OnButtonPressClose);
- connect(m_view->upgradeAllButton, &QPushButton::pressed, this, &Controller::OnButtonPressUpgrade);
- m_view->progressBar->setValue(0);
- m_view->progressBar->setVisible(false);
- UpgradeNotificationsBus::Handler::BusConnect();
- ModelNotificationsBus::Handler::BusConnect();
- }
- Controller::~Controller()
- {
- delete m_view;
- }
- void Controller::AddLogEntries()
- {
- const AZStd::vector<AZStd::string>* logs = nullptr;
- LogBus::BroadcastResult(logs, &LogTraits::GetEntries);
- if (!logs || logs->empty())
- {
- return;
- }
- const QTextCursor oldCursor = m_view->textEdit->textCursor();
- QScrollBar* scrollBar = m_view->textEdit->verticalScrollBar();
- m_view->textEdit->moveCursor(QTextCursor::End);
- QTextCursor textCursor = m_view->textEdit->textCursor();
- for (auto& entry : *logs)
- {
- textCursor.insertText("\n");
- textCursor.insertText(entry.c_str());
- }
- scrollBar->setValue(scrollBar->maximum());
- m_view->textEdit->moveCursor(QTextCursor::StartOfLine);
- LogBus::Broadcast(&LogTraits::Clear);
- }
- void Controller::EnableAllUpgradeButtons()
- {
- for (int row = 0; row < m_view->tableWidget->rowCount(); ++row)
- {
- if (QPushButton* button = qobject_cast<QPushButton*>(m_view->tableWidget->cellWidget(row, ColumnAction)))
- {
- button->setEnabled(true);
- }
- }
- }
- QList<QTableWidgetItem*> Controller::FindTableItems(const SourceHandle& info)
- {
- return m_view->tableWidget->findItems(info.RelativePath().c_str(), Qt::MatchFlag::MatchExactly);
- }
- void Controller::OnButtonPressClose()
- {
- reject();
- }
- void Controller::OnButtonPressScan()
- {
- // \todo move to another file
- auto isUpToDate = [this](const SourceHandle& asset)
- {
- auto graphComponent = asset.Get();
- AZ_Warning
- ( ScriptCanvas::k_VersionExplorerWindow.data()
- , asset.Get() != nullptr
- , "InspectAsset: %s, failed to load valid graph"
- , asset.RelativePath().c_str());
- return graphComponent &&
- (!graphComponent->GetVersion().IsLatest() || graphComponent->HasDeprecatedNode() || m_view->forceUpgrade->isChecked())
- ? ScanConfiguration::Filter::Include
- : ScanConfiguration::Filter::Exclude;
- };
- ScanConfiguration config;
- config.reportFilteredGraphs = !m_view->onlyShowOutdated->isChecked();
- config.onlyIncludeLegacyXML = m_view->onlyShowXMLFiles->isChecked();
- config.filter = isUpToDate;
- SetLoggingPreferences();
- ModelRequestsBus::Broadcast(&ModelRequestsTraits::Scan, config);
- }
- void Controller::OnButtonPressUpgrade()
- {
- OnButtonPressUpgradeImplementation({});
- }
- void Controller::OnButtonPressUpgradeImplementation(const SourceHandle& assetInfo)
- {
- auto simpleUpdate = [this](SourceHandle& asset)
- {
- AZ_Warning(ScriptCanvas::k_VersionExplorerWindow.data(), asset.Get() != nullptr
- , "The Script Canvas asset must have a Graph component");
- if (asset.Get())
- {
- UpgradeGraphConfig config;
- config.isVerbose = m_view->verbose->isChecked();
- config.saveParseErrors = m_view->saveParserFailures->isChecked();
- asset.Mod()->UpgradeGraph
- ( asset
- , m_view->forceUpgrade->isChecked() ? EditorGraph::UpgradeRequest::Forced : EditorGraph::UpgradeRequest::IfOutOfDate
- , config);
- }
- };
- auto onReadyOnlyFile = [this]()->bool
- {
- int result = QMessageBox::No;
- QMessageBox mb
- ( QMessageBox::Warning
- , QObject::tr("Failed to Save Upgraded File")
- , QObject::tr("The upgraded file could not be saved because the file is read only.\n"
- "Do you want to make it writeable and overwrite it?")
- , QMessageBox::YesToAll | QMessageBox::Yes | QMessageBox::No
- , this);
- result = mb.exec();
- return result == QMessageBox::YesToAll;
- };
- SetLoggingPreferences();
- ModifyConfiguration config;
- config.modifySingleAsset = assetInfo;
- config.modification = simpleUpdate;
- config.onReadOnlyFile = onReadyOnlyFile;
- config.backupGraphBeforeModification = m_view->makeBackupCheckbox->isChecked();
- ModelRequestsBus::Broadcast(&ModelRequestsTraits::Modify, config);
- }
- void Controller::OnButtonPressUpgradeSingle(const SourceHandle& info)
- {
- OnButtonPressUpgradeImplementation(info);
- }
- void Controller::OnUpgradeDependencyWaitInterval([[maybe_unused]] const SourceHandle& info)
- {
- AddLogEntries();
- }
- void Controller::OnUpgradeModificationBegin([[maybe_unused]] const ModifyConfiguration& config, const SourceHandle& info)
- {
- for (auto* item : FindTableItems(info))
- {
- int row = item->row();
- SetRowBusy(row);
- m_view->tableWidget->setCellWidget(row, ColumnAction, nullptr);
- }
- }
- void Controller::OnUpgradeModificationEnd
- ( [[maybe_unused]] const ModifyConfiguration& config
- , const SourceHandle& info
- , ModificationResult result)
- {
- if (result.errorMessage.empty())
- {
- VE_LOG("Successfully modified %s", result.asset.RelativePath().c_str());
- }
- else
- {
- VE_LOG("Failed to modify %s: %s", result.asset.RelativePath().c_str(), result.errorMessage.data());
- AZ_Warning(ScriptCanvas::k_VersionExplorerWindow.data()
- , false, "Failed to modify %s: %s", result.asset.RelativePath().c_str(), result.errorMessage.data());
- }
- for (auto* item : FindTableItems(info))
- {
- int row = item->row();
- if (result.errorMessage.empty())
- {
- SetRowSucceeded(row);
- }
- else
- {
- SetRowFailed(row, "");
- if (QPushButton* button = qobject_cast<QPushButton*>(m_view->tableWidget->cellWidget(row, ColumnAction)))
- {
- button->setEnabled(false);
- }
- }
- }
- m_view->progressBar->setVisible(true);
- ++m_handledAssetCount;
- m_view->progressBar->setValue(m_handledAssetCount);
- AddLogEntries();
- }
- void Controller::OnGraphUpgradeComplete(SourceHandle& asset, bool skipped)
- {
- ModificationResult result;
- result.asset = asset;
- if (skipped)
- {
- result.errorMessage = "Failed in editor upgrade state machine - check logs";
- }
- ModificationNotificationsBus::Broadcast(&ModificationNotificationsTraits::ModificationComplete, result);
- }
- void Controller::OnScanBegin(size_t assetCount)
- {
- // Reset rows
- m_handledAssetCount = 0;
- m_view->tableWidget->setRowCount(0);
- // Show progress bar and spinner
- m_view->progressBar->setRange(0, aznumeric_cast<int>(assetCount));
- m_view->progressBar->setValue(0);
- m_view->progressBar->setVisible(true);
- QString spinnerText = QStringLiteral("Scan in progress - gathering graphs that can be updated");
- m_view->spinner->SetText(spinnerText);
- SetSpinnerIsBusy(true);
- // Disable buttons
- m_view->scanButton->setEnabled(false);
- m_view->upgradeAllButton->setEnabled(false);
- m_view->closeButton->setEnabled(false);
- m_view->makeBackupCheckbox->setEnabled(false);
- m_view->onlyShowOutdated->setEnabled(false);
- m_view->onlyShowXMLFiles->setEnabled(false);
- }
- void Controller::OnScanComplete(const ScanResult& result)
- {
- // Enable buttons
- m_view->onlyShowXMLFiles->setEnabled(true);
- m_view->onlyShowOutdated->setEnabled(true);
- m_view->makeBackupCheckbox->setEnabled(true);
- m_view->closeButton->setEnabled(true);
- if (!result.m_unfiltered.empty())
- {
- m_view->upgradeAllButton->setEnabled(true);
- }
- m_view->scanButton->setEnabled(true);
- EnableAllUpgradeButtons();
- // Hide progress bar and show scan result
- m_view->progressBar->setVisible(false);
- m_view->progressBar->setValue(0);
- QString spinnerText = QStringLiteral("Scan Complete");
- spinnerText.append(QString::asprintf(" - Discovered: %zu, Failed: %zu, Upgradeable: %zu, Up-to-date: %zu"
- , result.m_catalogAssets.size()
- , result.m_loadErrors.size()
- , result.m_unfiltered.size()
- , result.m_filteredAssets.size()));
- m_view->spinner->SetText(spinnerText);
- SetSpinnerIsBusy(false);
- }
- void Controller::OnScanFilteredGraph(const SourceHandle& info)
- {
- OnScannedGraph(info, Filtered::Yes);
- }
- void Controller::OnScannedGraph(const SourceHandle& assetInfo, [[maybe_unused]] Filtered filtered)
- {
- const int rowIndex = m_view->tableWidget->rowCount();
- if (filtered == Filtered::No || !m_view->onlyShowOutdated->isChecked())
- {
- m_view->tableWidget->insertRow(rowIndex);
- QTableWidgetItem* rowName = new QTableWidgetItem(tr(assetInfo.RelativePath().c_str()));
- m_view->tableWidget->setItem(rowIndex, static_cast<int>(ColumnAsset), rowName);
- SetRowSucceeded(rowIndex);
- if (filtered == Filtered::No)
- {
- QPushButton* upgradeButton = new QPushButton(this);
- upgradeButton->setText("Upgrade");
- upgradeButton->setEnabled(false);
- SetRowBusy(rowIndex);
- connect
- ( upgradeButton
- , &QPushButton::pressed
- , this
- , [this, assetInfo]()
- {
- this->OnButtonPressUpgradeSingle(assetInfo);
- });
- m_view->tableWidget->setCellWidget(rowIndex, static_cast<int>(ColumnAction), upgradeButton);
- }
-
- bool result = false;
- AZ::Data::AssetInfo info;
- AZStd::string watchFolder;
- QByteArray assetNameUtf8 = assetInfo.RelativePath().c_str();
- AzToolsFramework::AssetSystemRequestBus::BroadcastResult
- ( result
- , &AzToolsFramework::AssetSystemRequestBus::Events::GetSourceInfoBySourcePath
- , assetNameUtf8
- , info
- , watchFolder);
- AZ_Error
- ( ScriptCanvas::k_VersionExplorerWindow.data()
- , result
- , "Failed to locate asset info for '%s'.", assetNameUtf8.constData());
- QToolButton* browseButton = new QToolButton(this);
- browseButton->setToolTip(AzQtComponents::fileBrowserActionName());
- browseButton->setIcon(QIcon(":/stylesheet/img/UI20/browse-edit.svg"));
- QString absolutePath = QDir(watchFolder.c_str()).absoluteFilePath(info.m_relativePath.c_str());
- connect(browseButton, &QPushButton::clicked, [absolutePath] {
- AzQtComponents::ShowFileOnDesktop(absolutePath);
- });
- m_view->tableWidget->setCellWidget(rowIndex, static_cast<int>(ColumnBrowse), browseButton);
- }
- OnScannedGraphResult(assetInfo);
- }
- void Controller::OnScannedGraphResult([[maybe_unused]] const SourceHandle& info)
- {
- m_view->progressBar->setValue(aznumeric_cast<int>(m_handledAssetCount));
- ++m_handledAssetCount;
- AddLogEntries();
- }
- void Controller::OnScanLoadFailure(const SourceHandle& info)
- {
- const int rowIndex = m_view->tableWidget->rowCount();
- m_view->tableWidget->insertRow(rowIndex);
- QTableWidgetItem* rowName = new QTableWidgetItem
- ( tr(AZStd::string::format("Load Error: %s", info.AbsolutePath().c_str()).c_str()));
- m_view->tableWidget->setItem(rowIndex, static_cast<int>(ColumnAsset), rowName);
- SetRowFailed(rowIndex, "Load failed");
- OnScannedGraphResult(info);
- }
- void Controller::OnScanUnFilteredGraph(const SourceHandle& info)
- {
- OnScannedGraph(info, Filtered::No);
- }
- void Controller::OnUpgradeBegin
- ( const ModifyConfiguration& config
- , [[maybe_unused]] const AZStd::vector<SourceHandle>& assets)
- {
- QString spinnerText = QStringLiteral("Upgrade in progress - ");
- if (!config.modifySingleAsset.RelativePath().empty())
- {
- spinnerText.append(" single graph");
- if (assets.size() == 1)
- {
- for (auto* item : FindTableItems(assets.front()))
- {
- int row = item->row();
- SetRowBusy(row);
- }
- }
- }
- else
- {
- for (int row = 0; row < m_view->tableWidget->rowCount(); ++row)
- {
- if (QPushButton* button = qobject_cast<QPushButton*>(m_view->tableWidget->cellWidget(row, ColumnAction)))
- {
- button->setEnabled(false);
- }
- SetRowBusy(row);
- }
- spinnerText.append(" all scanned graphs");
- }
- m_view->spinner->SetText(spinnerText);
- SetSpinnerIsBusy(true);
- }
- void Controller::SetLoggingPreferences()
- {
- LogBus::Broadcast(&LogTraits::SetVerbose, m_view->verbose->isChecked());
- LogBus::Broadcast(&LogTraits::SetVersionExporerExclusivity, m_view->updateReportingOnly->isChecked());
- }
- void Controller::SetSpinnerIsBusy(bool isBusy)
- {
- m_view->spinner->SetIsBusy(isBusy);
- m_view->spinner->SetBusyIconSize(16);
- }
- void Controller::OnUpgradeComplete(const ModificationResults& result)
- {
- QString spinnerText = QStringLiteral("Upgrade Complete - ");
- spinnerText.append(QString::asprintf(" - Upgraded: %zu, Failed: %zu"
- , result.m_successes.size()
- , result.m_failures.size()));
- m_view->spinner->SetText(spinnerText);
- SetSpinnerIsBusy(false);
- AddLogEntries();
- EnableAllUpgradeButtons();
- m_view->scanButton->setEnabled(true);
- }
- void Controller::OnUpgradeDependenciesGathered(const SourceHandle& info, Result result)
- {
- for (auto* item : FindTableItems(info))
- {
- int row = item->row();
- if (result == Result::Success)
- {
- SetRowSucceeded(row);
- }
- else
- {
- SetRowFailed(row, "");
- }
- if (QPushButton* button = qobject_cast<QPushButton*>(m_view->tableWidget->cellWidget(row, ColumnAction)))
- {
- button->setEnabled(true);
- }
- }
- m_view->progressBar->setVisible(true);
- ++m_handledAssetCount;
- m_view->progressBar->setValue(m_handledAssetCount);
- AddLogEntries();
- }
- void Controller::OnUpgradeDependencySortBegin
- ( [[maybe_unused]] const ModifyConfiguration& config
- , const AZStd::vector<SourceHandle>& assets)
- {
- m_handledAssetCount = 0;
- m_view->progressBar->setVisible(true);
- m_view->progressBar->setRange(0, aznumeric_caster(assets.size()));
- m_view->progressBar->setValue(0);
- m_view->scanButton->setEnabled(false);
- m_view->upgradeAllButton->setEnabled(false);
- m_view->onlyShowOutdated->setEnabled(false);
- for (int row = 0; row != m_view->tableWidget->rowCount(); ++row)
- {
- if (QPushButton* button = qobject_cast<QPushButton*>(m_view->tableWidget->cellWidget(row, ColumnAction)))
- {
- button->setEnabled(false);
- SetRowBusy(row);
- }
- }
- QString spinnerText = QStringLiteral("Upgrade in progress - gathering dependencies for the scanned graphs");
- m_view->spinner->SetText(spinnerText);
- SetSpinnerIsBusy(true);
- }
- void Controller::OnUpgradeDependencySortEnd
- ( [[maybe_unused]] const ModifyConfiguration& config
- , const AZStd::vector<SourceHandle>& assets
- , [[maybe_unused]] const AZStd::vector<size_t>& sortedOrder)
- {
- m_handledAssetCount = 0;
- m_view->progressBar->setRange(0, aznumeric_caster(assets.size()));
- m_view->progressBar->setValue(0);
- m_view->progressBar->setVisible(true);
- for (int row = 0; row != m_view->tableWidget->rowCount(); ++row)
- {
- if (QPushButton* button = qobject_cast<QPushButton*>(m_view->tableWidget->cellWidget(row, ColumnAction)))
- {
- button->setEnabled(false);
- SetRowPending(row);
- }
- }
- QString spinnerText = QStringLiteral("Upgrade in progress - gathering dependencies is complete");
- m_view->spinner->SetText(spinnerText);
- SetSpinnerIsBusy(false);
- AddLogEntries();
- }
- void Controller::SetRowBusy(int index)
- {
- if (index >= m_view->tableWidget->rowCount())
- {
- return;
- }
- AzQtComponents::StyledBusyLabel* busy = new AzQtComponents::StyledBusyLabel(this);
- busy->SetBusyIconSize(16);
- m_view->tableWidget->setCellWidget(index, ColumnStatus, busy);
- }
- void Controller::SetRowFailed(int index, AZStd::string_view message)
- {
- if (index >= m_view->tableWidget->rowCount())
- {
- return;
- }
- QToolButton* doneButton = new QToolButton(this);
- doneButton->setIcon(QIcon(":/Application/titlebar-close.svg"));
- doneButton->setToolTip(message.data());
- m_view->tableWidget->setCellWidget(index, ColumnStatus, doneButton);
- }
- void Controller::SetRowPending(int index)
- {
- m_view->tableWidget->removeCellWidget(index, ColumnStatus);
- }
- void Controller::SetRowsBusy()
- {
- for (int i = 0; i != m_view->tableWidget->rowCount(); ++i)
- {
- SetRowBusy(i);
- }
- }
- void Controller::SetRowSucceeded(int index)
- {
- if (index >= m_view->tableWidget->rowCount())
- {
- return;
- }
- QToolButton* doneButton = new QToolButton(this);
- doneButton->setIcon(QIcon(":/stylesheet/img/UI20/checkmark-menu.svg"));
- m_view->tableWidget->setCellWidget(index, ColumnStatus, doneButton);
- }
- }
- }
|