You cannot select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
796 lines
32 KiB
C++
796 lines
32 KiB
C++
/*
|
|
* 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 "native/utilities/GUIApplicationManager.h"
|
|
#include "native/connection/connectionManager.h"
|
|
#include "native/utilities/IniConfiguration.h"
|
|
#include "native/utilities/GUIApplicationServer.h"
|
|
#include "native/resourcecompiler/rccontroller.h"
|
|
#include "native/FileServer/fileServer.h"
|
|
#include "native/AssetManager/assetScanner.h"
|
|
|
|
#include <QApplication>
|
|
#include <QDialogButtonBox>
|
|
#include <QLabel>
|
|
#include <QMessageBox>
|
|
#include <QSettings>
|
|
|
|
#include <AzQtComponents/Components/StyleManager.h>
|
|
#include <AzQtComponents/Components/WindowDecorationWrapper.h>
|
|
#include <AzCore/Settings/SettingsRegistryMergeUtils.h>
|
|
#include <AzCore/Utils/Utils.h>
|
|
|
|
#if defined(EXTERNAL_CRASH_REPORTING)
|
|
#include <ToolsCrashHandler.h>
|
|
#endif
|
|
|
|
#if defined(AZ_PLATFORM_MAC)
|
|
#include <native/utilities/MacDockIconHandler.h>
|
|
#include <ApplicationServices/ApplicationServices.h>
|
|
#endif
|
|
#include <QJsonArray>
|
|
#include <QJsonDocument>
|
|
#include <QJsonObject>
|
|
#include <QSettings>
|
|
|
|
using namespace AssetProcessor;
|
|
|
|
namespace
|
|
{
|
|
static const int s_errorMessageBoxDelay = 5000;
|
|
|
|
void RemoveTemporaries()
|
|
{
|
|
// get currently running app
|
|
QFileInfo moduleFileInfo;
|
|
char executableDirectory[AZ_MAX_PATH_LEN];
|
|
AZ::Utils::GetExecutablePathReturnType result = AZ::Utils::GetExecutablePath(executableDirectory, AZStd::size(executableDirectory));
|
|
if (result.m_pathStored == AZ::Utils::ExecutablePathResult::Success)
|
|
{
|
|
moduleFileInfo.setFile(executableDirectory);
|
|
}
|
|
|
|
QDir binaryDir = moduleFileInfo.absoluteDir();
|
|
// strip extension
|
|
QString applicationBase = moduleFileInfo.completeBaseName();
|
|
// add wildcard filter
|
|
applicationBase.append("*_tmp");
|
|
// set to qt
|
|
binaryDir.setNameFilters(QStringList() << applicationBase);
|
|
binaryDir.setFilter(QDir::Files);
|
|
// iterate all matching
|
|
foreach(QString tempFile, binaryDir.entryList())
|
|
{
|
|
binaryDir.remove(tempFile);
|
|
}
|
|
}
|
|
|
|
}
|
|
|
|
|
|
GUIApplicationManager::GUIApplicationManager(int* argc, char*** argv, QObject* parent)
|
|
: ApplicationManagerBase(argc, argv, parent)
|
|
{
|
|
#if defined(AZ_PLATFORM_MAC)
|
|
// Since AP is not shipped as a '.app' package, it will not receive keyboard focus
|
|
// unless we tell the OS specifically to treat it as a foreground application.
|
|
ProcessSerialNumber psn = { 0, kCurrentProcess };
|
|
TransformProcessType(&psn, kProcessTransformToForegroundApplication);
|
|
#endif
|
|
}
|
|
|
|
|
|
GUIApplicationManager::~GUIApplicationManager()
|
|
{
|
|
Destroy();
|
|
}
|
|
|
|
|
|
|
|
ApplicationManager::BeforeRunStatus GUIApplicationManager::BeforeRun()
|
|
{
|
|
AssetProcessor::MessageInfoBus::Handler::BusConnect();
|
|
|
|
ApplicationManager::BeforeRunStatus status = ApplicationManagerBase::BeforeRun();
|
|
if (status != ApplicationManager::BeforeRunStatus::Status_Success)
|
|
{
|
|
return status;
|
|
}
|
|
|
|
// The build process may leave behind some temporaries, try to delete them
|
|
RemoveTemporaries();
|
|
|
|
QDir projectAssetRoot;
|
|
AssetUtilities::ComputeAssetRoot(projectAssetRoot);
|
|
#if defined(EXTERNAL_CRASH_REPORTING)
|
|
CrashHandler::ToolsCrashHandler::InitCrashHandler("AssetProcessor", projectAssetRoot.absolutePath().toStdString());
|
|
#endif
|
|
|
|
// we have to monitor both the cache folder and the database file and restart AP if either of them gets deleted
|
|
// It is important to note that we are monitoring the parent folder and not the actual cache folder itself since
|
|
// we want to handle the use case on Mac OS if the user moves the cache folder to the trash.
|
|
m_qtFileWatcher.addPath(projectAssetRoot.absolutePath());
|
|
|
|
QDir projectCacheRoot;
|
|
AssetUtilities::ComputeProjectCacheRoot(projectCacheRoot);
|
|
QString assetDbPath = projectCacheRoot.filePath("assetdb.sqlite");
|
|
|
|
m_qtFileWatcher.addPath(assetDbPath);
|
|
|
|
// if our Gems file changes, make sure we watch that, too.
|
|
QString projectPath = AssetUtilities::ComputeProjectPath();
|
|
|
|
QObject::connect(&m_qtFileWatcher, &QFileSystemWatcher::fileChanged, this, &GUIApplicationManager::FileChanged);
|
|
QObject::connect(&m_qtFileWatcher, &QFileSystemWatcher::directoryChanged, this, &GUIApplicationManager::DirectoryChanged);
|
|
|
|
return ApplicationManager::BeforeRunStatus::Status_Success;
|
|
}
|
|
|
|
void GUIApplicationManager::Destroy()
|
|
{
|
|
if (m_mainWindow)
|
|
{
|
|
delete m_mainWindow;
|
|
m_mainWindow = nullptr;
|
|
}
|
|
|
|
AssetProcessor::MessageInfoBus::Handler::BusDisconnect();
|
|
ApplicationManagerBase::Destroy();
|
|
|
|
DestroyIniConfiguration();
|
|
DestroyFileServer();
|
|
}
|
|
|
|
|
|
bool GUIApplicationManager::Run()
|
|
{
|
|
qRegisterMetaType<AZ::u32>("AZ::u32");
|
|
qRegisterMetaType<AZ::Uuid>("AZ::Uuid");
|
|
|
|
AZ::IO::FixedMaxPath engineRootPath;
|
|
if (auto settingsRegistry = AZ::SettingsRegistry::Get(); settingsRegistry != nullptr)
|
|
{
|
|
settingsRegistry->Get(engineRootPath.Native(), AZ::SettingsRegistryMergeUtils::FilePathKey_EngineRootFolder);
|
|
}
|
|
AzQtComponents::StyleManager* styleManager = new AzQtComponents::StyleManager(qApp);
|
|
styleManager->initialize(qApp, engineRootPath);
|
|
|
|
QDir engineRoot;
|
|
AssetUtilities::ComputeAssetRoot(engineRoot);
|
|
AssetUtilities::ComputeEngineRoot(engineRoot);
|
|
AzQtComponents::StyleManager::addSearchPaths(
|
|
QStringLiteral("style"),
|
|
engineRoot.filePath(QStringLiteral("Code/Tools/AssetProcessor/native/ui/style")),
|
|
QStringLiteral(":/AssetProcessor/style"),
|
|
engineRootPath);
|
|
|
|
m_mainWindow = new MainWindow(this);
|
|
auto wrapper = new AzQtComponents::WindowDecorationWrapper(
|
|
#if defined(AZ_PLATFORM_WINDOWS)
|
|
// On windows we do want our custom title bar
|
|
AzQtComponents::WindowDecorationWrapper::OptionAutoAttach
|
|
#else
|
|
// On others platforms we don't want our custom title bar (ie, use native title bars).
|
|
AzQtComponents::WindowDecorationWrapper::OptionDisabled
|
|
#endif
|
|
);
|
|
wrapper->setGuest(m_mainWindow);
|
|
|
|
// Use this variant of the enableSaveRestoreGeometry because the global QCoreApplication::setOrganization and setApplicationName
|
|
// are called in ApplicationManager::Activate, which happens much later on in this function.
|
|
// ApplicationManager::Activate is shared between the Batch version of the AP and the GUI version,
|
|
// and there are thing
|
|
const bool restoreOnFirstShow = true;
|
|
wrapper->enableSaveRestoreGeometry(GetOrganizationName(), GetApplicationName(), "MainWindow", restoreOnFirstShow);
|
|
|
|
AzQtComponents::StyleManager::setStyleSheet(m_mainWindow, QStringLiteral("style:AssetProcessor.qss"));
|
|
|
|
auto refreshStyleSheets = [styleManager]()
|
|
{
|
|
styleManager->Refresh();
|
|
};
|
|
|
|
// CheckForRegistryProblems can pop up a dialog, so we need to check after
|
|
// we initialize the stylesheet
|
|
bool showErrorMessageOnRegistryProblem = true;
|
|
RegistryCheckInstructions registryCheckInstructions = CheckForRegistryProblems(m_mainWindow, showErrorMessageOnRegistryProblem);
|
|
if (registryCheckInstructions != RegistryCheckInstructions::Continue)
|
|
{
|
|
if (registryCheckInstructions == RegistryCheckInstructions::Restart)
|
|
{
|
|
Restart();
|
|
}
|
|
|
|
return false;
|
|
}
|
|
|
|
bool startHidden = QApplication::arguments().contains("--start-hidden", Qt::CaseInsensitive);
|
|
|
|
if (!startHidden)
|
|
{
|
|
wrapper->show();
|
|
}
|
|
else
|
|
{
|
|
#ifdef AZ_PLATFORM_WINDOWS
|
|
// Qt / Windows has issues if the main window isn't shown once
|
|
// so we show it then hide it
|
|
wrapper->show();
|
|
|
|
// Have a delay on the hide, to make sure that the show is entirely processed
|
|
// first
|
|
QTimer::singleShot(0, wrapper, &QWidget::hide);
|
|
#endif
|
|
}
|
|
|
|
#ifdef AZ_PLATFORM_MAC
|
|
connect(new MacDockIconHandler(this), &MacDockIconHandler::dockIconClicked, m_mainWindow, &MainWindow::ShowWindow);
|
|
#endif
|
|
|
|
QAction* quitAction = new QAction(QObject::tr("Quit"), m_mainWindow);
|
|
quitAction->setShortcut(QKeySequence(Qt::CTRL + Qt::Key_Q));
|
|
quitAction->setMenuRole(QAction::QuitRole);
|
|
m_mainWindow->addAction(quitAction);
|
|
m_mainWindow->connect(quitAction, SIGNAL(triggered()), this, SLOT(QuitRequested()));
|
|
|
|
QAction* refreshAction = new QAction(QObject::tr("Refresh Stylesheet"), m_mainWindow);
|
|
refreshAction->setShortcut(QKeySequence(Qt::CTRL + Qt::Key_R));
|
|
m_mainWindow->addAction(refreshAction);
|
|
m_mainWindow->connect(refreshAction, &QAction::triggered, this, refreshStyleSheets);
|
|
|
|
QObject::connect(this, &GUIApplicationManager::ShowWindow, m_mainWindow, &MainWindow::ShowWindow);
|
|
|
|
|
|
if (QSystemTrayIcon::isSystemTrayAvailable())
|
|
{
|
|
QAction* showAction = new QAction(QObject::tr("Show"), m_mainWindow);
|
|
QObject::connect(showAction, &QAction::triggered, m_mainWindow, &MainWindow::ShowWindow);
|
|
QAction* hideAction = new QAction(QObject::tr("Hide"), m_mainWindow);
|
|
QObject::connect(hideAction, &QAction::triggered, wrapper, &AzQtComponents::WindowDecorationWrapper::hide);
|
|
|
|
QMenu* trayIconMenu = new QMenu();
|
|
trayIconMenu->addAction(showAction);
|
|
trayIconMenu->addAction(hideAction);
|
|
trayIconMenu->addSeparator();
|
|
|
|
#if AZ_TRAIT_OS_PLATFORM_APPLE
|
|
QAction* systemTrayQuitAction = new QAction(QObject::tr("Quit"), m_mainWindow);
|
|
systemTrayQuitAction->setMenuRole(QAction::NoRole);
|
|
m_mainWindow->connect(systemTrayQuitAction, SIGNAL(triggered()), this, SLOT(QuitRequested()));
|
|
trayIconMenu->addAction(systemTrayQuitAction);
|
|
#else
|
|
trayIconMenu->addAction(quitAction);
|
|
#endif
|
|
|
|
m_trayIcon = new QSystemTrayIcon(QIcon(":/o3de_assetprocessor_taskbar.svg"), m_mainWindow);
|
|
m_trayIcon->setContextMenu(trayIconMenu);
|
|
m_trayIcon->setToolTip(QObject::tr("O3DE Asset Processor"));
|
|
m_trayIcon->show();
|
|
QObject::connect(m_trayIcon, &QSystemTrayIcon::activated, m_mainWindow, [&, wrapper](QSystemTrayIcon::ActivationReason reason)
|
|
{
|
|
if (reason == QSystemTrayIcon::DoubleClick)
|
|
{
|
|
if (wrapper->isVisible())
|
|
{
|
|
wrapper->hide();
|
|
}
|
|
else
|
|
{
|
|
m_mainWindow->ShowWindow();
|
|
}
|
|
}
|
|
});
|
|
|
|
QObject::connect(m_trayIcon, &QSystemTrayIcon::messageClicked, m_mainWindow, &MainWindow::ShowWindow);
|
|
|
|
if (startHidden)
|
|
{
|
|
m_trayIcon->showMessage(
|
|
QCoreApplication::translate("Tray Icon", "O3DE Asset Processor has started"),
|
|
QCoreApplication::translate("Tray Icon", "The O3DE Asset Processor monitors raw project assets and converts those assets into runtime-ready data."),
|
|
QSystemTrayIcon::Information, 3000);
|
|
}
|
|
}
|
|
|
|
connect(this, &GUIApplicationManager::AssetProcessorStatusChanged, m_mainWindow, &MainWindow::OnAssetProcessorStatusChanged);
|
|
|
|
if (!Activate())
|
|
{
|
|
return false;
|
|
}
|
|
|
|
m_mainWindow->Activate();
|
|
|
|
connect(GetAssetScanner(), &AssetProcessor::AssetScanner::AssetScanningStatusChanged, this, [this](AssetScanningStatus status)
|
|
{
|
|
if (status == AssetScanningStatus::Started)
|
|
{
|
|
AssetProcessor::AssetProcessorStatusEntry entry(AssetProcessor::AssetProcessorStatus::Scanning_Started);
|
|
m_mainWindow->OnAssetProcessorStatusChanged(entry);
|
|
}
|
|
});
|
|
connect(GetRCController(), &AssetProcessor::RCController::ActiveJobsCountChanged, this, &GUIApplicationManager::OnActiveJobsCountChanged);
|
|
connect(this, &GUIApplicationManager::ConnectionStatusMsg, this, &GUIApplicationManager::ShowTrayIconMessage);
|
|
|
|
qApp->setQuitOnLastWindowClosed(false);
|
|
|
|
m_duringStartup = false;
|
|
m_startedSuccessfully = true;
|
|
|
|
int resultCode = qApp->exec(); // this blocks until the last window is closed.
|
|
|
|
if(!InitiatedShutdown())
|
|
{
|
|
// if we are here it implies that AP did not stop the Qt event loop and is shutting down prematurely
|
|
// we need to call QuitRequested and start the event loop once again so that AP shuts down correctly
|
|
QuitRequested();
|
|
resultCode = qApp->exec();
|
|
}
|
|
|
|
if (m_trayIcon)
|
|
{
|
|
m_trayIcon->hide();
|
|
delete m_trayIcon;
|
|
}
|
|
|
|
m_mainWindow->SaveLogPanelState();
|
|
|
|
// mainWindow indirectly uses some UserSettings so clean it up before we clean those up
|
|
delete m_mainWindow;
|
|
m_mainWindow = nullptr;
|
|
|
|
AZ::SerializeContext* context;
|
|
EBUS_EVENT_RESULT(context, AZ::ComponentApplicationBus, GetSerializeContext);
|
|
AZ_Assert(context, "No serialize context");
|
|
QDir projectCacheRoot;
|
|
AssetUtilities::ComputeProjectCacheRoot(projectCacheRoot);
|
|
m_localUserSettings.Save(projectCacheRoot.filePath("AssetProcessorUserSettings.xml").toUtf8().data(), context);
|
|
m_localUserSettings.Deactivate();
|
|
|
|
if (NeedRestart())
|
|
{
|
|
bool launched = Restart();
|
|
if (!launched)
|
|
{
|
|
return false;
|
|
}
|
|
}
|
|
|
|
Destroy();
|
|
|
|
return !resultCode && m_startedSuccessfully;
|
|
}
|
|
|
|
void GUIApplicationManager::NegotiationFailed()
|
|
{
|
|
QString message = QCoreApplication::translate("error", "An attempt to connect to the game or editor has failed. The game or editor appears to be running from a different folder or a different project. Please restart the asset processor from the correct branch or make sure the game/editor is running the same project as the asset processor.");
|
|
QMetaObject::invokeMethod(this, "ShowMessageBox", Qt::QueuedConnection, Q_ARG(QString, QString("Negotiation Failed")), Q_ARG(QString, message), Q_ARG(bool, false));
|
|
}
|
|
|
|
void GUIApplicationManager::OnAssetFailed(const AZStd::string& sourceFileName)
|
|
{
|
|
QString message = tr("Error : %1 failed to compile\nPlease check the Asset Processor for more information.").arg(QString::fromUtf8(sourceFileName.c_str()));
|
|
QMetaObject::invokeMethod(this, "ShowTrayIconErrorMessage", Qt::QueuedConnection, Q_ARG(QString, message));
|
|
}
|
|
|
|
void GUIApplicationManager::OnErrorMessage(const char* error)
|
|
{
|
|
QMessageBox msgBox;
|
|
msgBox.setText(QCoreApplication::translate("errors", error));
|
|
msgBox.setStandardButtons(QMessageBox::Ok);
|
|
msgBox.setDefaultButton(QMessageBox::Ok);
|
|
msgBox.exec();
|
|
}
|
|
|
|
void GUIApplicationManager::ShowMessageBox(QString title, QString msg, bool isCritical)
|
|
{
|
|
if (!m_messageBoxIsVisible)
|
|
{
|
|
// Only show the message box if it is not visible
|
|
m_messageBoxIsVisible = true;
|
|
QMessageBox msgBox(m_mainWindow);
|
|
msgBox.setWindowTitle(title);
|
|
msgBox.setText(msg);
|
|
msgBox.setStandardButtons(QMessageBox::Ok);
|
|
msgBox.setDefaultButton(QMessageBox::Ok);
|
|
if (isCritical)
|
|
{
|
|
msgBox.setIcon(QMessageBox::Critical);
|
|
}
|
|
msgBox.exec();
|
|
m_messageBoxIsVisible = false;
|
|
}
|
|
}
|
|
|
|
bool GUIApplicationManager::OnError(const char* /*window*/, const char* message)
|
|
{
|
|
// if we're in a worker thread, errors must not pop up a dialog box
|
|
if (AssetProcessor::GetThreadLocalJobId() != 0)
|
|
{
|
|
// just absorb the error, do not perform default op
|
|
return true;
|
|
}
|
|
|
|
// If we're the main thread, then consider showing the message box directly.
|
|
// note that all other threads will PAUSE if they emit a message while the main thread is showing this box
|
|
// due to the way the trace system EBUS is mutex-protected.
|
|
Qt::ConnectionType connection = Qt::DirectConnection;
|
|
|
|
if (QThread::currentThread() != qApp->thread())
|
|
{
|
|
connection = Qt::QueuedConnection;
|
|
}
|
|
|
|
QMetaObject::invokeMethod(this, "ShowMessageBox", connection, Q_ARG(QString, QString("Error")), Q_ARG(QString, QString(message)), Q_ARG(bool, true));
|
|
|
|
return true;
|
|
}
|
|
|
|
bool GUIApplicationManager::OnAssert(const char* message)
|
|
{
|
|
if (!OnError(nullptr, message))
|
|
{
|
|
return false;
|
|
}
|
|
|
|
// Asserts should be severe enough for data corruption,
|
|
// so the process should quit to avoid that happening for users.
|
|
if (!AZ::Debug::Trace::IsDebuggerPresent())
|
|
{
|
|
QuitRequested();
|
|
return true;
|
|
}
|
|
|
|
AZ::Debug::Trace::Break();
|
|
return true;
|
|
}
|
|
|
|
bool GUIApplicationManager::Activate()
|
|
{
|
|
AZ::SerializeContext* context;
|
|
EBUS_EVENT_RESULT(context, AZ::ComponentApplicationBus, GetSerializeContext);
|
|
AZ_Assert(context, "No serialize context");
|
|
QDir projectCacheRoot;
|
|
AssetUtilities::ComputeProjectCacheRoot(projectCacheRoot);
|
|
m_localUserSettings.Load(projectCacheRoot.filePath("AssetProcessorUserSettings.xml").toUtf8().data(), context);
|
|
m_localUserSettings.Activate(AZ::UserSettings::CT_LOCAL);
|
|
|
|
InitIniConfiguration();
|
|
InitFileServer();
|
|
|
|
//activate the base stuff.
|
|
if (!ApplicationManagerBase::Activate())
|
|
{
|
|
return false;
|
|
}
|
|
|
|
return true;
|
|
}
|
|
|
|
bool GUIApplicationManager::PostActivate()
|
|
{
|
|
if (!ApplicationManagerBase::PostActivate())
|
|
{
|
|
m_startedSuccessfully = false;
|
|
return false;
|
|
}
|
|
|
|
m_fileWatcher->StartWatching();
|
|
|
|
return true;
|
|
}
|
|
|
|
void GUIApplicationManager::CreateQtApplication()
|
|
{
|
|
QCoreApplication::setAttribute(Qt::AA_EnableHighDpiScaling);
|
|
QCoreApplication::setAttribute(Qt::AA_UseHighDpiPixmaps);
|
|
QCoreApplication::setAttribute(Qt::AA_ShareOpenGLContexts);
|
|
QGuiApplication::setHighDpiScaleFactorRoundingPolicy(Qt::HighDpiScaleFactorRoundingPolicy::PassThrough);
|
|
|
|
// Qt actually modifies the argc and argv, you must pass the real ones in as ref so it can.
|
|
m_qApp = new QApplication(*m_frameworkApp.GetArgC(), *m_frameworkApp.GetArgV());
|
|
}
|
|
|
|
void GUIApplicationManager::DirectoryChanged([[maybe_unused]] QString path)
|
|
{
|
|
QDir projectCacheRoot;
|
|
AssetUtilities::ComputeProjectCacheRoot(projectCacheRoot);
|
|
if (!projectCacheRoot.exists() || !projectCacheRoot.exists("assetdb.sqlite"))
|
|
{
|
|
// If either the Cache directory or database file has been removed, we need to restart
|
|
QTimer::singleShot(200, this, [this]()
|
|
{
|
|
QMetaObject::invokeMethod(this, "Restart", Qt::QueuedConnection);
|
|
});
|
|
}
|
|
}
|
|
|
|
void GUIApplicationManager::FileChanged(QString path)
|
|
{
|
|
QDir projectCacheRoot;
|
|
AssetUtilities::ComputeProjectCacheRoot(projectCacheRoot);
|
|
QString assetDbPath = projectCacheRoot.filePath("assetdb.sqlite");
|
|
if (QString::compare(AssetUtilities::NormalizeFilePath(path), assetDbPath, Qt::CaseInsensitive) == 0)
|
|
{
|
|
if (!QFile::exists(assetDbPath))
|
|
{
|
|
// if the database file is deleted we need to restart
|
|
QTimer::singleShot(200, this, [this]()
|
|
{
|
|
QMetaObject::invokeMethod(this, "Restart", Qt::QueuedConnection);
|
|
});
|
|
}
|
|
}
|
|
}
|
|
|
|
bool GUIApplicationManager::InitApplicationServer()
|
|
{
|
|
m_applicationServer = new GUIApplicationServer();
|
|
return true;
|
|
}
|
|
|
|
void GUIApplicationManager::InitConnectionManager()
|
|
{
|
|
ApplicationManagerBase::InitConnectionManager();
|
|
|
|
using namespace std::placeholders;
|
|
using namespace AzFramework::AssetSystem;
|
|
using namespace AzToolsFramework::AssetSystem;
|
|
|
|
//File Server related
|
|
m_connectionManager->RegisterService(FileOpenRequest::MessageType, std::bind(&FileServer::ProcessOpenRequest, m_fileServer, _1, _2, _3, _4));
|
|
m_connectionManager->RegisterService(FileCloseRequest::MessageType, std::bind(&FileServer::ProcessCloseRequest, m_fileServer, _1, _2, _3, _4));
|
|
m_connectionManager->RegisterService(FileReadRequest::MessageType, std::bind(&FileServer::ProcessReadRequest, m_fileServer, _1, _2, _3, _4));
|
|
m_connectionManager->RegisterService(FileWriteRequest::MessageType, std::bind(&FileServer::ProcessWriteRequest, m_fileServer, _1, _2, _3, _4));
|
|
m_connectionManager->RegisterService(FileSeekRequest::MessageType, std::bind(&FileServer::ProcessSeekRequest, m_fileServer, _1, _2, _3, _4));
|
|
m_connectionManager->RegisterService(FileTellRequest::MessageType, std::bind(&FileServer::ProcessTellRequest, m_fileServer, _1, _2, _3, _4));
|
|
m_connectionManager->RegisterService(FileIsReadOnlyRequest::MessageType, std::bind(&FileServer::ProcessIsReadOnlyRequest, m_fileServer, _1, _2, _3, _4));
|
|
m_connectionManager->RegisterService(PathIsDirectoryRequest::MessageType, std::bind(&FileServer::ProcessIsDirectoryRequest, m_fileServer, _1, _2, _3, _4));
|
|
m_connectionManager->RegisterService(FileSizeRequest::MessageType, std::bind(&FileServer::ProcessSizeRequest, m_fileServer, _1, _2, _3, _4));
|
|
m_connectionManager->RegisterService(FileModTimeRequest::MessageType, std::bind(&FileServer::ProcessModificationTimeRequest, m_fileServer, _1, _2, _3, _4));
|
|
m_connectionManager->RegisterService(FileExistsRequest::MessageType, std::bind(&FileServer::ProcessExistsRequest, m_fileServer, _1, _2, _3, _4));
|
|
m_connectionManager->RegisterService(FileFlushRequest::MessageType, std::bind(&FileServer::ProcessFlushRequest, m_fileServer, _1, _2, _3, _4));
|
|
m_connectionManager->RegisterService(PathCreateRequest::MessageType, std::bind(&FileServer::ProcessCreatePathRequest, m_fileServer, _1, _2, _3, _4));
|
|
m_connectionManager->RegisterService(PathDestroyRequest::MessageType, std::bind(&FileServer::ProcessDestroyPathRequest, m_fileServer, _1, _2, _3, _4));
|
|
m_connectionManager->RegisterService(FileRemoveRequest::MessageType, std::bind(&FileServer::ProcessRemoveRequest, m_fileServer, _1, _2, _3, _4));
|
|
m_connectionManager->RegisterService(FileCopyRequest::MessageType, std::bind(&FileServer::ProcessCopyRequest, m_fileServer, _1, _2, _3, _4));
|
|
m_connectionManager->RegisterService(FileRenameRequest::MessageType, std::bind(&FileServer::ProcessRenameRequest, m_fileServer, _1, _2, _3, _4));
|
|
m_connectionManager->RegisterService(FindFilesRequest::MessageType, std::bind(&FileServer::ProcessFindFileNamesRequest, m_fileServer, _1, _2, _3, _4));
|
|
|
|
m_connectionManager->RegisterService(FileTreeRequest::MessageType, std::bind(&FileServer::ProcessFileTreeRequest, m_fileServer, _1, _2, _3, _4));
|
|
|
|
|
|
QObject::connect(m_connectionManager, SIGNAL(connectionAdded(uint, Connection*)), m_fileServer, SLOT(ConnectionAdded(unsigned int, Connection*)));
|
|
QObject::connect(m_connectionManager, SIGNAL(ConnectionDisconnected(unsigned int)), m_fileServer, SLOT(ConnectionRemoved(unsigned int)));
|
|
|
|
QObject::connect(m_fileServer, SIGNAL(AddBytesReceived(unsigned int, qint64, bool)), m_connectionManager, SLOT(AddBytesReceived(unsigned int, qint64, bool)));
|
|
QObject::connect(m_fileServer, SIGNAL(AddBytesSent(unsigned int, qint64, bool)), m_connectionManager, SLOT(AddBytesSent(unsigned int, qint64, bool)));
|
|
QObject::connect(m_fileServer, SIGNAL(AddBytesRead(unsigned int, qint64, bool)), m_connectionManager, SLOT(AddBytesRead(unsigned int, qint64, bool)));
|
|
QObject::connect(m_fileServer, SIGNAL(AddBytesWritten(unsigned int, qint64, bool)), m_connectionManager, SLOT(AddBytesWritten(unsigned int, qint64, bool)));
|
|
QObject::connect(m_fileServer, SIGNAL(AddOpenRequest(unsigned int, bool)), m_connectionManager, SLOT(AddOpenRequest(unsigned int, bool)));
|
|
QObject::connect(m_fileServer, SIGNAL(AddCloseRequest(unsigned int, bool)), m_connectionManager, SLOT(AddCloseRequest(unsigned int, bool)));
|
|
QObject::connect(m_fileServer, SIGNAL(AddOpened(unsigned int, bool)), m_connectionManager, SLOT(AddOpened(unsigned int, bool)));
|
|
QObject::connect(m_fileServer, SIGNAL(AddClosed(unsigned int, bool)), m_connectionManager, SLOT(AddClosed(unsigned int, bool)));
|
|
QObject::connect(m_fileServer, SIGNAL(AddReadRequest(unsigned int, bool)), m_connectionManager, SLOT(AddReadRequest(unsigned int, bool)));
|
|
QObject::connect(m_fileServer, SIGNAL(AddWriteRequest(unsigned int, bool)), m_connectionManager, SLOT(AddWriteRequest(unsigned int, bool)));
|
|
QObject::connect(m_fileServer, SIGNAL(AddTellRequest(unsigned int, bool)), m_connectionManager, SLOT(AddTellRequest(unsigned int, bool)));
|
|
QObject::connect(m_fileServer, SIGNAL(AddSeekRequest(unsigned int, bool)), m_connectionManager, SLOT(AddSeekRequest(unsigned int, bool)));
|
|
QObject::connect(m_fileServer, SIGNAL(AddIsReadOnlyRequest(unsigned int, bool)), m_connectionManager, SLOT(AddIsReadOnlyRequest(unsigned int, bool)));
|
|
QObject::connect(m_fileServer, SIGNAL(AddIsDirectoryRequest(unsigned int, bool)), m_connectionManager, SLOT(AddIsDirectoryRequest(unsigned int, bool)));
|
|
QObject::connect(m_fileServer, SIGNAL(AddSizeRequest(unsigned int, bool)), m_connectionManager, SLOT(AddSizeRequest(unsigned int, bool)));
|
|
QObject::connect(m_fileServer, SIGNAL(AddModificationTimeRequest(unsigned int, bool)), m_connectionManager, SLOT(AddModificationTimeRequest(unsigned int, bool)));
|
|
QObject::connect(m_fileServer, SIGNAL(AddExistsRequest(unsigned int, bool)), m_connectionManager, SLOT(AddExistsRequest(unsigned int, bool)));
|
|
QObject::connect(m_fileServer, SIGNAL(AddFlushRequest(unsigned int, bool)), m_connectionManager, SLOT(AddFlushRequest(unsigned int, bool)));
|
|
QObject::connect(m_fileServer, SIGNAL(AddCreatePathRequest(unsigned int, bool)), m_connectionManager, SLOT(AddCreatePathRequest(unsigned int, bool)));
|
|
QObject::connect(m_fileServer, SIGNAL(AddDestroyPathRequest(unsigned int, bool)), m_connectionManager, SLOT(AddDestroyPathRequest(unsigned int, bool)));
|
|
QObject::connect(m_fileServer, SIGNAL(AddRemoveRequest(unsigned int, bool)), m_connectionManager, SLOT(AddRemoveRequest(unsigned int, bool)));
|
|
QObject::connect(m_fileServer, SIGNAL(AddCopyRequest(unsigned int, bool)), m_connectionManager, SLOT(AddCopyRequest(unsigned int, bool)));
|
|
QObject::connect(m_fileServer, SIGNAL(AddRenameRequest(unsigned int, bool)), m_connectionManager, SLOT(AddRenameRequest(unsigned int, bool)));
|
|
QObject::connect(m_fileServer, SIGNAL(AddFindFileNamesRequest(unsigned int, bool)), m_connectionManager, SLOT(AddFindFileNamesRequest(unsigned int, bool)));
|
|
QObject::connect(m_fileServer, SIGNAL(UpdateConnectionMetrics()), m_connectionManager, SLOT(UpdateConnectionMetrics()));
|
|
|
|
m_connectionManager->RegisterService(ShowAssetProcessorRequest::MessageType,
|
|
std::bind([this](unsigned int /*connId*/, unsigned int /*type*/, unsigned int /*serial*/, QByteArray /*payload*/)
|
|
{
|
|
Q_EMIT ShowWindow();
|
|
}, std::placeholders::_1, std::placeholders::_2, std::placeholders::_3, std::placeholders::_4)
|
|
);
|
|
|
|
m_connectionManager->RegisterService(ShowAssetInAssetProcessorRequest::MessageType,
|
|
std::bind([this](unsigned int /*connId*/, unsigned int /*type*/, unsigned int /*serial*/, QByteArray payload)
|
|
{
|
|
ShowAssetInAssetProcessorRequest request;
|
|
bool readFromStream = AZ::Utils::LoadObjectFromBufferInPlace(payload.data(), payload.size(), request);
|
|
AZ_Assert(readFromStream, "GUIApplicationManager::ShowAssetInAssetProcessorRequest: Could not deserialize from stream");
|
|
if (readFromStream)
|
|
{
|
|
m_mainWindow->HighlightAsset(request.m_assetPath.c_str());
|
|
|
|
Q_EMIT ShowWindow();
|
|
}
|
|
}, std::placeholders::_1, std::placeholders::_2, std::placeholders::_3, std::placeholders::_4)
|
|
);
|
|
}
|
|
|
|
void GUIApplicationManager::InitIniConfiguration()
|
|
{
|
|
m_iniConfiguration = new IniConfiguration();
|
|
m_iniConfiguration->readINIConfigFile();
|
|
m_iniConfiguration->parseCommandLine();
|
|
}
|
|
|
|
void GUIApplicationManager::DestroyIniConfiguration()
|
|
{
|
|
if (m_iniConfiguration)
|
|
{
|
|
delete m_iniConfiguration;
|
|
m_iniConfiguration = nullptr;
|
|
}
|
|
}
|
|
|
|
void GUIApplicationManager::InitFileServer()
|
|
{
|
|
m_fileServer = new FileServer();
|
|
m_fileServer->SetSystemRoot(GetSystemRoot());
|
|
}
|
|
|
|
void GUIApplicationManager::DestroyFileServer()
|
|
{
|
|
if (m_fileServer)
|
|
{
|
|
delete m_fileServer;
|
|
m_fileServer = nullptr;
|
|
}
|
|
}
|
|
|
|
IniConfiguration* GUIApplicationManager::GetIniConfiguration() const
|
|
{
|
|
return m_iniConfiguration;
|
|
}
|
|
|
|
FileServer* GUIApplicationManager::GetFileServer() const
|
|
{
|
|
return m_fileServer;
|
|
}
|
|
|
|
void GUIApplicationManager::ShowTrayIconErrorMessage(QString msg)
|
|
{
|
|
AZStd::chrono::system_clock::time_point currentTime = AZStd::chrono::system_clock::now();
|
|
|
|
if (m_trayIcon && m_mainWindow)
|
|
{
|
|
if((currentTime - m_timeWhenLastWarningWasShown) >= AZStd::chrono::milliseconds(s_errorMessageBoxDelay))
|
|
{
|
|
m_timeWhenLastWarningWasShown = currentTime;
|
|
m_trayIcon->showMessage(
|
|
QCoreApplication::translate("Tray Icon", "O3DE Asset Processor"),
|
|
QCoreApplication::translate("Tray Icon", msg.toUtf8().data()),
|
|
QSystemTrayIcon::Critical, 3000);
|
|
}
|
|
}
|
|
}
|
|
|
|
void GUIApplicationManager::ShowTrayIconMessage(QString msg)
|
|
{
|
|
if (m_trayIcon && m_mainWindow && !m_mainWindow->isVisible())
|
|
{
|
|
m_trayIcon->showMessage(
|
|
QCoreApplication::translate("Tray Icon", "O3DE Asset Processor"),
|
|
QCoreApplication::translate("Tray Icon", msg.toUtf8().data()),
|
|
QSystemTrayIcon::Information, 3000);
|
|
}
|
|
}
|
|
|
|
bool GUIApplicationManager::Restart()
|
|
{
|
|
bool launched = QProcess::startDetached(QCoreApplication::applicationFilePath(), QCoreApplication::arguments());
|
|
if (!launched)
|
|
{
|
|
QMessageBox::critical(nullptr,
|
|
QCoreApplication::translate("application", "Unable to launch Asset Processor"),
|
|
QCoreApplication::translate("application", "Unable to launch Asset Processor"));
|
|
}
|
|
|
|
return launched;
|
|
}
|
|
|
|
void GUIApplicationManager::Reflect()
|
|
{
|
|
AZ::SerializeContext* context;
|
|
EBUS_EVENT_RESULT(context, AZ::ComponentApplicationBus, GetSerializeContext);
|
|
AZ_Assert(context, "No serialize context");
|
|
AzToolsFramework::LogPanel::BaseLogPanel::Reflect(context);
|
|
}
|
|
|
|
const char* GUIApplicationManager::GetLogBaseName()
|
|
{
|
|
return "AP_GUI";
|
|
}
|
|
|
|
ApplicationManager::RegistryCheckInstructions GUIApplicationManager::PopupRegistryProblemsMessage(QString warningText)
|
|
{
|
|
warningText = warningText.arg(tr("Click the Restart button"));
|
|
|
|
// Doing all of this as a custom dialog because QMessageBox
|
|
// has a fixed width, which doesn't display the extremely large
|
|
// block of warning text well.
|
|
QDialog dialog(nullptr, Qt::WindowCloseButtonHint | Qt::WindowTitleHint);
|
|
dialog.setWindowTitle("Asset Processor Error");
|
|
|
|
QVBoxLayout* layout = new QVBoxLayout(&dialog);
|
|
layout->addSpacing(16);
|
|
|
|
QHBoxLayout* messageLayout = new QHBoxLayout(&dialog);
|
|
QLabel* icon = new QLabel("", &dialog);
|
|
QPixmap errorIcon(":/stylesheet/img/lineedit-invalid.png");
|
|
errorIcon = errorIcon.scaled(errorIcon.size() * 4);
|
|
icon->setPixmap(errorIcon);
|
|
icon->setMaximumSize(errorIcon.size());
|
|
QLabel* label = new QLabel(warningText, &dialog);
|
|
messageLayout->addWidget(icon);
|
|
messageLayout->addSpacing(16);
|
|
messageLayout->addWidget(label);
|
|
layout->addLayout(messageLayout);
|
|
|
|
layout->addSpacing(16);
|
|
|
|
QDialogButtonBox* buttons = new QDialogButtonBox(&dialog);
|
|
QPushButton* exitButton = buttons->addButton(tr("Exit"), QDialogButtonBox::RejectRole);
|
|
connect(exitButton, &QPushButton::pressed, &dialog, &QDialog::reject);
|
|
QPushButton* restartButton = buttons->addButton(tr("Restart"), QDialogButtonBox::AcceptRole);
|
|
connect(restartButton, &QPushButton::pressed, &dialog, &QDialog::accept);
|
|
layout->addWidget(buttons);
|
|
|
|
if (dialog.exec() == QDialog::Accepted)
|
|
{
|
|
return RegistryCheckInstructions::Restart;
|
|
}
|
|
else
|
|
{
|
|
return RegistryCheckInstructions::Exit;
|
|
}
|
|
}
|
|
|
|
void GUIApplicationManager::InitSourceControl()
|
|
{
|
|
QSettings settings;
|
|
settings.beginGroup("Settings");
|
|
bool enableSourceControl = settings.value("EnableSourceControl", 1).toBool();
|
|
|
|
const AzFramework::CommandLine* commandLine = nullptr;
|
|
AzFramework::ApplicationRequests::Bus::BroadcastResult(commandLine, &AzFramework::ApplicationRequests::GetCommandLine);
|
|
|
|
if (commandLine->HasSwitch("enablescm"))
|
|
{
|
|
enableSourceControl = true;
|
|
}
|
|
|
|
if (enableSourceControl)
|
|
{
|
|
AzToolsFramework::SourceControlConnectionRequestBus::Broadcast(&AzToolsFramework::SourceControlConnectionRequestBus::Events::EnableSourceControl, true);
|
|
}
|
|
else
|
|
{
|
|
Q_EMIT SourceControlReady();
|
|
}
|
|
}
|
|
|
|
bool GUIApplicationManager::GetShouldExitOnIdle() const
|
|
{
|
|
bool shouldExit = false;
|
|
const AzFramework::CommandLine* commandLine = nullptr;
|
|
AzFramework::ApplicationRequests::Bus::BroadcastResult(commandLine, &AzFramework::ApplicationRequests::GetCommandLine);
|
|
|
|
if (commandLine->HasSwitch("quitonidle"))
|
|
{
|
|
shouldExit = true;
|
|
}
|
|
|
|
return shouldExit;
|
|
}
|
|
|