/* * 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 #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include AZ_PUSH_DISABLE_WARNING(4251 4800, "-Wunknown-warning-option") // disable warnings spawned by QT #include #include #include AZ_POP_DISABLE_WARNING namespace AtomToolsFramework { bool SaveSettingsToFile(const AZ::IO::FixedMaxPath& savePath, const AZStd::vector& filters) { auto registry = AZ::SettingsRegistry::Get(); if (registry == nullptr) { AZ_Warning("AtomToolsFramework", false, "Unable to access global settings registry."); return false; } AZ::SettingsRegistryMergeUtils::DumperSettings dumperSettings; dumperSettings.m_prettifyOutput = true; dumperSettings.m_includeFilter = [filters](AZStd::string_view path) { for (const auto& filter : filters) { if (filter.starts_with(path.substr(0, filter.size()))) { return true; } } return false; }; AZStd::string stringBuffer; AZ::IO::ByteContainerStream stringStream(&stringBuffer); if (!AZ::SettingsRegistryMergeUtils::DumpSettingsRegistryToStream(*registry, "", stringStream, dumperSettings)) { AZ_Warning("AtomToolsFramework", false, R"(Unable to save changes to the registry file at "%s"\n)", savePath.c_str()); return false; } bool saved = false; constexpr auto configurationMode = AZ::IO::SystemFile::SF_OPEN_CREATE | AZ::IO::SystemFile::SF_OPEN_CREATE_PATH | AZ::IO::SystemFile::SF_OPEN_WRITE_ONLY; if (AZ::IO::SystemFile outputFile; outputFile.Open(savePath.c_str(), configurationMode)) { saved = outputFile.Write(stringBuffer.data(), stringBuffer.size()) == stringBuffer.size(); } AZ_Warning("AtomToolsFramework", saved, R"(Unable to save registry file to path "%s"\n)", savePath.c_str()); return saved; } void LoadImageAsync(const AZStd::string& path, LoadImageAsyncCallback callback) { AZ::Job* job = AZ::CreateJobFunction( [path, callback]() { ImageProcessingAtom::IImageObjectPtr imageObject; ImageProcessingAtom::ImageProcessingRequestBus::BroadcastResult( imageObject, &ImageProcessingAtom::ImageProcessingRequests::LoadImagePreview, path); if (imageObject) { AZ::u8* imageBuf = nullptr; AZ::u32 pitch = 0; AZ::u32 mip = 0; imageObject->GetImagePointer(mip, imageBuf, pitch); const AZ::u32 width = imageObject->GetWidth(mip); const AZ::u32 height = imageObject->GetHeight(mip); QImage image(imageBuf, width, height, pitch, QImage::Format_RGBA8888); if (callback) { callback(image); } } }, true); job->Start(); } QFileInfo GetSaveFileInfo(const QString& initialPath) { const QFileInfo initialFileInfo(initialPath); const QString initialExt(initialFileInfo.completeSuffix()); // Instead of just passing in the absolute file path, we pass in the absolute folder path and the base name to prevent the file // dialog from displaying multiple extensions when the extension contains a "." const QFileInfo selectedFileInfo(AzQtComponents::FileDialog::GetSaveFileName( QApplication::activeWindow(), "Save File", initialFileInfo.absolutePath() + AZ_CORRECT_FILESYSTEM_SEPARATOR_STRING + initialFileInfo.baseName(), QString("Files (*.%1)").arg(initialExt))); if (selectedFileInfo.absoluteFilePath().isEmpty()) { // Cancelled operation return QFileInfo(); } if (!selectedFileInfo.absoluteFilePath().endsWith(initialExt)) { QMessageBox::critical(QApplication::activeWindow(), "Error", QString("File name must have .%1 extension.").arg(initialExt)); return QFileInfo(); } // Reconstructing the file info from the absolute path and expected extension to compensate for an issue with the save file // dialog adding the extension multiple times if it contains "." like *.lightingpreset.azasset return QFileInfo(selectedFileInfo.absolutePath() + AZ_CORRECT_FILESYSTEM_SEPARATOR_STRING + selectedFileInfo.baseName() + "." + initialExt); } QFileInfo GetOpenFileInfo(const AZStd::vector& assetTypes) { using namespace AZ::Data; using namespace AzToolsFramework::AssetBrowser; // [GFX TODO] Should this just be an open file dialog filtered to supported source data extensions? auto selection = AssetSelectionModel::AssetTypesSelection(assetTypes); // [GFX TODO] This is functional but UI is not as designed AssetBrowserComponentRequestBus::Broadcast(&AssetBrowserComponentRequests::PickAssets, selection, QApplication::activeWindow()); if (!selection.IsValid()) { return QFileInfo(); } auto entry = selection.GetResult(); const SourceAssetBrowserEntry* sourceEntry = azrtti_cast(entry); if (!sourceEntry) { const ProductAssetBrowserEntry* productEntry = azrtti_cast(entry); if (productEntry) { sourceEntry = azrtti_cast(productEntry->GetParent()); } } if (!sourceEntry) { return QFileInfo(); } return QFileInfo(sourceEntry->GetFullPath().c_str()); } QFileInfo GetUniqueFileInfo(const QString& initialPath) { int counter = 0; QFileInfo fileInfo = initialPath; const QString extension = "." + fileInfo.completeSuffix(); const QString basePathAndName = fileInfo.absoluteFilePath().left(fileInfo.absoluteFilePath().size() - extension.size()); while (fileInfo.exists()) { fileInfo = QString("%1_%2%3").arg(basePathAndName).arg(++counter).arg(extension); } return fileInfo; } QFileInfo GetDuplicationFileInfo(const QString& initialPath) { const QFileInfo initialFileInfo(initialPath); const QString initialExt(initialFileInfo.completeSuffix()); const QFileInfo duplicateFileInfo(AzQtComponents::FileDialog::GetSaveFileName( QApplication::activeWindow(), "Duplicate File", GetUniqueFileInfo(initialPath).absoluteFilePath(), QString("Files (*.%1)").arg(initialExt))); if (duplicateFileInfo == initialFileInfo) { // Cancelled operation or selected same path return QFileInfo(); } if (duplicateFileInfo.absoluteFilePath().isEmpty()) { // Cancelled operation or selected same path return QFileInfo(); } if (!duplicateFileInfo.absoluteFilePath().endsWith(initialExt)) { QMessageBox::critical(QApplication::activeWindow(), "Error", QString("File name must have .%1 extension.").arg(initialExt)); return QFileInfo(); } return duplicateFileInfo; } bool LaunchTool(const QString& baseName, const QStringList& arguments) { AZ::IO::FixedMaxPath engineRoot = AZ::Utils::GetEnginePath(); AZ_Assert(!engineRoot.empty(), "Cannot query Engine Path"); AZ::IO::FixedMaxPath launchPath = AZ::IO::FixedMaxPath(AZ::Utils::GetExecutableDirectory()) / (baseName + AZ_TRAIT_OS_EXECUTABLE_EXTENSION).toUtf8().constData(); return QProcess::startDetached(launchPath.c_str(), arguments, engineRoot.c_str()); } AZStd::string GetExteralReferencePath( const AZStd::string& exportPath, const AZStd::string& referencePath, const bool relativeToExportPath) { if (referencePath.empty()) { return {}; } if (!relativeToExportPath) { AZStd::string watchFolder; AZ::Data::AssetInfo assetInfo; bool sourceInfoFound = false; AzToolsFramework::AssetSystemRequestBus::BroadcastResult( sourceInfoFound, &AzToolsFramework::AssetSystemRequestBus::Events::GetSourceInfoBySourcePath, referencePath.c_str(), assetInfo, watchFolder); if (sourceInfoFound) { return assetInfo.m_relativePath; } } AZ::IO::BasicPath exportFolder(exportPath); exportFolder.RemoveFilename(); return AZ::IO::PathView(referencePath).LexicallyRelative(exportFolder).StringAsPosix(); } template bool ComparePropertyValues(const AZStd::any& valueA, const AZStd::any& valueB) { return valueA.is() && valueB.is() && *AZStd::any_cast(&valueA) == *AZStd::any_cast(&valueB); } bool ArePropertyValuesEqual(const AZStd::any& valueA, const AZStd::any& valueB) { if (valueA.type() != valueB.type()) { return false; } if (ComparePropertyValues(valueA, valueB) || ComparePropertyValues(valueA, valueB) || ComparePropertyValues(valueA, valueB) || ComparePropertyValues(valueA, valueB) || ComparePropertyValues(valueA, valueB) || ComparePropertyValues(valueA, valueB) || ComparePropertyValues(valueA, valueB) || ComparePropertyValues(valueA, valueB) || ComparePropertyValues(valueA, valueB) || ComparePropertyValues>(valueA, valueB) || ComparePropertyValues>(valueA, valueB) || ComparePropertyValues>(valueA, valueB) || ComparePropertyValues>(valueA, valueB) || ComparePropertyValues>(valueA, valueB) || ComparePropertyValues(valueA, valueB)) { return true; } return false; } } // namespace AtomToolsFramework