Asset Bundler GUI (#427)
The AssetBundler is a new ToolsApplication that allows users to work through the entire Asset Bundling process without ever touching a command line. * Integrating github/AssetBundler through commit 1d65018 * Asset Bundler bug fixes: platform initialization and GUI styling (#5) * fixed enabled platform initialization * fixed the cached engine root. This fixed some of my Seeds tab data issues. The default Engine Seed List appeared, and was able to display the contents on screen. * updated my notes of active bugs * changed some casing in various include lines to hopefully fix my linux build * another include fix for linux * AssetBundler GUI is now compiling on Mac * removed some things off of my todo list because the mac build fix actually fixed the visuals! everything's the right color again * removed the word Lumberyard from the bundler * Asset bundler bug fixes - Bundles, Gems, and Tests (#9) * Fixed the Bundle loading and generation problem. Turned out to be a FileWatcher issue. * turns out gem loading wasn't broken, there were just no existing SeedListFiles for any of the gems loaded by the AutomatedTesting project. I added a default SeedListFile for the PrimitiveAssets Gem. * fixed some failing AssetBundler Gem tests * Misunderstood the need to have default seed lists for asset-only gems. removing the previously created seed list file * Asset bundler bug fixes: Seeds Tab display issues and _dependencies.xml loading (#10) * Fixed the Project Source column in the Seeds tab * The AssetBundler will no longer attempt to copy a template version of the ProjectName_dependencies.xml file into your active project. However, it will throw an error if you do not have one. A follow-up ticket has been cut to address this issue. * updated the AssetBundler icon. This one matches the current style guides * PR feedback: pass a const ref instead of a value * PR feedback: safer conversion from a string_view to a QString Co-authored-by: alexpete <alexpete@amazon.com>
This commit is contained in:
@@ -13,9 +13,13 @@ if(NOT PAL_TRAIT_BUILD_HOST_TOOLS)
|
||||
return()
|
||||
endif()
|
||||
|
||||
include(${CMAKE_CURRENT_SOURCE_DIR}/Platform/${PAL_PLATFORM_NAME}/PAL_${PAL_PLATFORM_NAME_LOWERCASE}.cmake)
|
||||
|
||||
# AssetBundlerBatch - CLI Application
|
||||
ly_add_target(
|
||||
NAME AssetBundler.Static STATIC
|
||||
NAME AssetBundlerBatch.Static STATIC
|
||||
NAMESPACE AZ
|
||||
AUTOMOC
|
||||
FILES_CMAKE
|
||||
assetbundlerbatch_files.cmake
|
||||
INCLUDE_DIRECTORIES
|
||||
@@ -23,6 +27,9 @@ ly_add_target(
|
||||
.
|
||||
BUILD_DEPENDENCIES
|
||||
PUBLIC
|
||||
3rdParty::Qt::Core
|
||||
3rdParty::Qt::Gui
|
||||
3rdParty::Qt::Widgets
|
||||
AZ::AzToolsFramework
|
||||
${additional_dependencies}
|
||||
)
|
||||
@@ -32,12 +39,41 @@ ly_add_target(
|
||||
NAMESPACE AZ
|
||||
FILES_CMAKE
|
||||
assetbundlerbatch_exe_files.cmake
|
||||
COMPILE_DEFINITIONS
|
||||
PRIVATE
|
||||
AB_BATCH_MODE
|
||||
INCLUDE_DIRECTORIES
|
||||
PRIVATE
|
||||
.
|
||||
BUILD_DEPENDENCIES
|
||||
PRIVATE
|
||||
AZ::AssetBundler.Static
|
||||
AZ::AssetBundlerBatch.Static
|
||||
)
|
||||
|
||||
# AssetBundler - Qt GUI Application
|
||||
ly_add_target(
|
||||
NAME AssetBundler ${PAL_TRAIT_BUILD_ASSETBUNDLER_APPLICATION_TYPE}
|
||||
NAMESPACE AZ
|
||||
AUTOMOC
|
||||
AUTOUIC
|
||||
AUTORCC
|
||||
FILES_CMAKE
|
||||
assetbundlergui_files.cmake
|
||||
assetbundler_exe_files.cmake
|
||||
Platform/${PAL_PLATFORM_NAME}/assetbundlergui_${PAL_PLATFORM_NAME_LOWERCASE}_files.cmake
|
||||
INCLUDE_DIRECTORIES
|
||||
PUBLIC
|
||||
Platform/${PAL_PLATFORM_NAME}
|
||||
PRIVATE
|
||||
.
|
||||
BUILD_DEPENDENCIES
|
||||
PUBLIC
|
||||
3rdParty::Qt::Core
|
||||
3rdParty::Qt::Gui
|
||||
3rdParty::Qt::Widgets
|
||||
AZ::AzToolsFramework
|
||||
AZ::AssetBundlerBatch.Static
|
||||
${additional_dependencies}
|
||||
)
|
||||
|
||||
if(PAL_TRAIT_BUILD_TESTS_SUPPORTED)
|
||||
@@ -53,7 +89,7 @@ if(PAL_TRAIT_BUILD_TESTS_SUPPORTED)
|
||||
BUILD_DEPENDENCIES
|
||||
PRIVATE
|
||||
AZ::AzTest
|
||||
AZ::AssetBundler.Static
|
||||
AZ::AssetBundlerBatch.Static
|
||||
AZ::AzFrameworkTestShared
|
||||
)
|
||||
|
||||
|
||||
@@ -0,0 +1,13 @@
|
||||
#
|
||||
# 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.
|
||||
#
|
||||
|
||||
set (PAL_TRAIT_BUILD_ASSETBUNDLER_APPLICATION_TYPE APPLICATION)
|
||||
|
||||
@@ -0,0 +1,14 @@
|
||||
#
|
||||
# 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.
|
||||
#
|
||||
|
||||
set(FILES
|
||||
source/utils/GUIApplicationManager_Linux.cpp
|
||||
)
|
||||
@@ -0,0 +1,21 @@
|
||||
/*
|
||||
* 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 <AzQtComponents/Components/WindowDecorationWrapper.h>
|
||||
|
||||
namespace Platform
|
||||
{
|
||||
AzQtComponents::WindowDecorationWrapper::Option GetWindowDecorationWrapperOption()
|
||||
{
|
||||
return AzQtComponents::WindowDecorationWrapper::OptionDisabled;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,13 @@
|
||||
#
|
||||
# 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.
|
||||
#
|
||||
|
||||
set (PAL_TRAIT_BUILD_ASSETBUNDLER_APPLICATION_TYPE APPLICATION)
|
||||
|
||||
@@ -0,0 +1,14 @@
|
||||
#
|
||||
# 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.
|
||||
#
|
||||
|
||||
set(FILES
|
||||
source/utils/GUIApplicationManager_OSX.cpp
|
||||
)
|
||||
@@ -0,0 +1,21 @@
|
||||
/*
|
||||
* 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 <AzQtComponents/Components/WindowDecorationWrapper.h>
|
||||
|
||||
namespace Platform
|
||||
{
|
||||
AzQtComponents::WindowDecorationWrapper::Option GetWindowDecorationWrapperOption()
|
||||
{
|
||||
return AzQtComponents::WindowDecorationWrapper::OptionDisabled;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,13 @@
|
||||
#
|
||||
# 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.
|
||||
#
|
||||
|
||||
set (PAL_TRAIT_BUILD_ASSETBUNDLER_APPLICATION_TYPE APPLICATION)
|
||||
|
||||
@@ -0,0 +1,14 @@
|
||||
#
|
||||
# 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.
|
||||
#
|
||||
|
||||
set(FILES
|
||||
source/utils/GUIApplicationManager_Win.cpp
|
||||
)
|
||||
@@ -0,0 +1,21 @@
|
||||
/*
|
||||
* 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 <AzQtComponents/Components/WindowDecorationWrapper.h>
|
||||
|
||||
namespace Platform
|
||||
{
|
||||
AzQtComponents::WindowDecorationWrapper::Option GetWindowDecorationWrapperOption()
|
||||
{
|
||||
return AzQtComponents::WindowDecorationWrapper::OptionAutoAttach;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,15 @@
|
||||
#
|
||||
# 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.
|
||||
#
|
||||
|
||||
set(FILES
|
||||
source/main.cpp
|
||||
source/AssetBundler.rc
|
||||
)
|
||||
@@ -0,0 +1,70 @@
|
||||
#
|
||||
# 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.
|
||||
#
|
||||
|
||||
set(FILES
|
||||
source/models/AssetBundlerAbstractFileTableModel.h
|
||||
source/models/AssetBundlerAbstractFileTableModel.cpp
|
||||
source/models/AssetBundlerFileTableFilterModel.h
|
||||
source/models/AssetBundlerFileTableFilterModel.cpp
|
||||
source/models/AssetListFileTableModel.h
|
||||
source/models/AssetListFileTableModel.cpp
|
||||
source/models/AssetListTableModel.cpp
|
||||
source/models/AssetListTableModel.h
|
||||
source/models/BundleFileListModel.h
|
||||
source/models/BundleFileListModel.cpp
|
||||
source/models/RulesFileTableModel.h
|
||||
source/models/RulesFileTableModel.cpp
|
||||
source/models/SeedListFileTableModel.h
|
||||
source/models/SeedListFileTableModel.cpp
|
||||
source/models/SeedListTableModel.h
|
||||
source/models/SeedListTableModel.cpp
|
||||
source/ui/style/AssetBundler.qrc
|
||||
source/ui/style/AssetBundler.qss
|
||||
source/ui/style/AssetBundlerConfig.ini
|
||||
source/ui/style/AssetBundler-Icon-256x256@x2.ico
|
||||
source/ui/AddSeedDialog.h
|
||||
source/ui/AddSeedDialog.cpp
|
||||
source/ui/AddSeedDialog.ui
|
||||
source/ui/AssetBundlerTabWidget.h
|
||||
source/ui/AssetBundlerTabWidget.cpp
|
||||
source/ui/AssetListTabWidget.h
|
||||
source/ui/AssetListTabWidget.cpp
|
||||
source/ui/AssetListTabWidget.ui
|
||||
source/ui/BundleListTabWidget.h
|
||||
source/ui/BundleListTabWidget.cpp
|
||||
source/ui/BundleListTabWidget.ui
|
||||
source/ui/ComparisonDataWidget.h
|
||||
source/ui/ComparisonDataWidget.cpp
|
||||
source/ui/ComparisonDataWidget.ui
|
||||
source/ui/EditSeedDialog.h
|
||||
source/ui/EditSeedDialog.cpp
|
||||
source/ui/EditSeedDialog.ui
|
||||
source/ui/GenerateBundlesModal.h
|
||||
source/ui/GenerateBundlesModal.cpp
|
||||
source/ui/GenerateBundlesModal.ui
|
||||
source/ui/MainWindow.h
|
||||
source/ui/MainWindow.cpp
|
||||
source/ui/MainWindow.ui
|
||||
source/ui/NewFileDialog.h
|
||||
source/ui/NewFileDialog.cpp
|
||||
source/ui/NewFileDialog.ui
|
||||
source/ui/PlatformSelectionWidget.h
|
||||
source/ui/PlatformSelectionWidget.cpp
|
||||
source/ui/PlatformSelectionWidget.ui
|
||||
source/ui/RulesTabWidget.h
|
||||
source/ui/RulesTabWidget.cpp
|
||||
source/ui/RulesTabWidget.ui
|
||||
source/ui/SeedTabWidget.h
|
||||
source/ui/SeedTabWidget.cpp
|
||||
source/ui/SeedTabWidget.ui
|
||||
source/utils/GUIApplicationManager.h
|
||||
source/utils/GUIApplicationManager.cpp
|
||||
)
|
||||
@@ -0,0 +1 @@
|
||||
IDI_ICON1 ICON DISCARDABLE "ui\\style\\AssetBundler-Icon-256x256@x2.ico"
|
||||
@@ -10,17 +10,48 @@
|
||||
*
|
||||
*/
|
||||
|
||||
#if defined(AB_BATCH_MODE)
|
||||
#include <source/utils/applicationManager.h>
|
||||
#else
|
||||
#include <source/utils/GUIApplicationManager.h>
|
||||
#include <AzQtComponents/Utilities/QtPluginPaths.h>
|
||||
#endif
|
||||
|
||||
#if defined(AZ_TESTS_ENABLED)
|
||||
#include <AzTest/AzTest.h>
|
||||
DECLARE_AZ_UNIT_TEST_MAIN();
|
||||
#endif
|
||||
|
||||
int main(int argc, char* argv[])
|
||||
{
|
||||
#if defined(AZ_TESTS_ENABLED)
|
||||
INVOKE_AZ_UNIT_TEST_MAIN();
|
||||
#endif
|
||||
|
||||
AZ::AllocatorInstance<AZ::SystemAllocator>::Create();
|
||||
int runSuccess = 0;
|
||||
|
||||
{
|
||||
AssetBundler::ApplicationManager applicationManger(&argc, &argv);
|
||||
applicationManger.Init();
|
||||
runSuccess = applicationManger.Run() ? 0 : 1;
|
||||
//This nested scope is necessary as the applicationManager needs to have its destructor called BEFORE you destroy the allocators
|
||||
|
||||
#if defined(AB_BATCH_MODE)
|
||||
AssetBundler::ApplicationManager applicationManager(&argc, &argv);
|
||||
#else
|
||||
// Must be called before using any Qt, or the app won't be able to locate Qt libs
|
||||
AzQtComponents::PrepareQtPaths();
|
||||
AssetBundler::GUIApplicationManager applicationManager(&argc, &argv);
|
||||
#endif
|
||||
if (!applicationManager.Init())
|
||||
{
|
||||
AZ_Error("AssetBundler", false, "AssetBundler initialization failed");
|
||||
runSuccess = 1;
|
||||
}
|
||||
else
|
||||
{
|
||||
runSuccess = applicationManager.Run() ? 0 : 1;
|
||||
}
|
||||
}
|
||||
|
||||
AZ::AllocatorInstance<AZ::SystemAllocator>::Destroy();
|
||||
return runSuccess;
|
||||
}
|
||||
|
||||
@@ -0,0 +1,233 @@
|
||||
/*
|
||||
* 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 <source/models/AssetBundlerAbstractFileTableModel.h>
|
||||
#include <source/utils/utils.h>
|
||||
|
||||
#include <AzFramework/IO/LocalFileIO.h>
|
||||
|
||||
#include <QSetIterator>
|
||||
|
||||
namespace AssetBundler
|
||||
{
|
||||
const char* DateTimeFormat = "hh:mm:ss MMM dd, yyyy";
|
||||
|
||||
AssetBundlerAbstractFileTableModel::AssetBundlerAbstractFileTableModel(QObject* parent)
|
||||
: QAbstractTableModel(parent)
|
||||
{
|
||||
}
|
||||
|
||||
void AssetBundlerAbstractFileTableModel::Reload(const char* fileExtension, const QSet<QString>& watchedFolders, const QSet<QString>& watchedFiles, const AZStd::unordered_map<AZStd::string, AZStd::string>& pathToProjectNameMap)
|
||||
{
|
||||
AZStd::vector<AZStd::string> keysToRemove = m_fileListKeys;
|
||||
|
||||
// Reload all the files in the watched folders
|
||||
QString filter = QString("*.%1").arg(fileExtension);
|
||||
|
||||
QSetIterator<QString> itr(watchedFolders);
|
||||
while (itr.hasNext())
|
||||
{
|
||||
QDir filesDir(itr.next());
|
||||
filesDir.setNameFilters({ filter });
|
||||
for (const QString& fileNameAndExtension : filesDir.entryList(QDir::Files))
|
||||
{
|
||||
AZStd::string absolutePath = filesDir.absoluteFilePath(fileNameAndExtension).toUtf8().data();
|
||||
AZStd::string projectName;
|
||||
if (pathToProjectNameMap.contains(absolutePath))
|
||||
{
|
||||
projectName = pathToProjectNameMap.at(absolutePath);
|
||||
}
|
||||
|
||||
// If a project name is already specified, then the associated file is a default file
|
||||
LoadFile(absolutePath, projectName, !projectName.empty());
|
||||
keysToRemove.erase(AZStd::remove(keysToRemove.begin(), keysToRemove.end(), AssetBundler::GenerateKeyFromAbsolutePath(absolutePath)), keysToRemove.end());
|
||||
}
|
||||
}
|
||||
|
||||
// Reload all the watched files
|
||||
for (const QString& filePath : watchedFiles)
|
||||
{
|
||||
AZStd::string absolutePath = filePath.toUtf8().data();
|
||||
if (AZ::IO::FileIOBase::GetInstance()->Exists(absolutePath.c_str()))
|
||||
{
|
||||
AZStd::string projectName = pathToProjectNameMap.at(absolutePath);
|
||||
|
||||
// If a project name is already specified, then the associated file is a default file
|
||||
LoadFile(absolutePath, projectName, !projectName.empty());
|
||||
keysToRemove.erase(AZStd::remove(keysToRemove.begin(), keysToRemove.end(), AssetBundler::GenerateKeyFromAbsolutePath(absolutePath)), keysToRemove.end());
|
||||
}
|
||||
}
|
||||
|
||||
//Remove nonexistant files from the model
|
||||
for (const AZStd::string& key : keysToRemove)
|
||||
{
|
||||
DeleteFileByKey(key);
|
||||
}
|
||||
}
|
||||
|
||||
void AssetBundlerAbstractFileTableModel::ReloadFiles(const AZStd::vector<AZStd::string>& absoluteFilePathList, AZStd::unordered_map<AZStd::string, AZStd::string> pathToProjectNameMap)
|
||||
{
|
||||
for (const AZStd::string& absoluteFilePath : absoluteFilePathList)
|
||||
{
|
||||
if (!AZ::IO::FileIOBase::GetInstance()->Exists(absoluteFilePath.c_str()))
|
||||
{
|
||||
// File is not present on-disk, make sure to remove it from the model
|
||||
DeleteFileByKey(AssetBundler::GenerateKeyFromAbsolutePath(absoluteFilePath));
|
||||
continue;
|
||||
}
|
||||
|
||||
// If a project name is already specified, then the associated file is a default file
|
||||
AZStd::string projectName = pathToProjectNameMap[absoluteFilePath];
|
||||
LoadFile(absoluteFilePath, projectName, !projectName.empty());
|
||||
}
|
||||
}
|
||||
|
||||
bool AssetBundlerAbstractFileTableModel::Save(const QModelIndex& selectedIndex)
|
||||
{
|
||||
if (!selectedIndex.isValid() || m_keysWithUnsavedChanges.empty())
|
||||
{
|
||||
// There is nothing to save
|
||||
return true;
|
||||
}
|
||||
|
||||
AZStd::string key = GetFileKey(selectedIndex);
|
||||
if (key.empty())
|
||||
{
|
||||
// Error has already been thrown
|
||||
return false;
|
||||
}
|
||||
|
||||
// Save the file
|
||||
if (!WriteToDisk(key))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
// Update the display
|
||||
m_keysWithUnsavedChanges.erase(key);
|
||||
QModelIndex topLeftIndex = index(selectedIndex.row(), 0);
|
||||
QModelIndex bottomRightIndex = index(selectedIndex.row(), columnCount() - 1);
|
||||
emit dataChanged(topLeftIndex, bottomRightIndex, { Qt::DisplayRole, Qt::FontRole });
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool AssetBundlerAbstractFileTableModel::SaveAll()
|
||||
{
|
||||
if (!HasUnsavedChanges())
|
||||
{
|
||||
// No need to update all of the elements if we are not changing anything
|
||||
return true;
|
||||
}
|
||||
|
||||
bool hasSaveErrors = false;
|
||||
|
||||
// Save every file with unsaved changes
|
||||
AZStd::unordered_set<AZStd::string> keysWithErrors;
|
||||
for (const AZStd::string& key : m_keysWithUnsavedChanges)
|
||||
{
|
||||
if (!WriteToDisk(key))
|
||||
{
|
||||
// Error has already been thrown
|
||||
hasSaveErrors = true;
|
||||
keysWithErrors.emplace(key);
|
||||
}
|
||||
}
|
||||
|
||||
m_keysWithUnsavedChanges = keysWithErrors;
|
||||
|
||||
// Update the display of all elements
|
||||
QModelIndex firstIndex = index(0, 0);
|
||||
QModelIndex lastIndex = index(rowCount() - 1, columnCount() - 1);
|
||||
emit dataChanged(firstIndex, lastIndex, { Qt::DisplayRole, Qt::FontRole });
|
||||
|
||||
return !hasSaveErrors;
|
||||
}
|
||||
|
||||
bool AssetBundlerAbstractFileTableModel::HasUnsavedChanges() const
|
||||
{
|
||||
return !m_keysWithUnsavedChanges.empty();
|
||||
}
|
||||
|
||||
int AssetBundlerAbstractFileTableModel::rowCount(const QModelIndex& /*parent*/) const
|
||||
{
|
||||
return static_cast<int>(m_fileListKeys.size());
|
||||
}
|
||||
|
||||
AZStd::string AssetBundlerAbstractFileTableModel::GetFileKey(const QModelIndex& index) const
|
||||
{
|
||||
int row = index.row();
|
||||
int col = index.column();
|
||||
if (row >= rowCount() || row < 0 || col >= columnCount() || col < 0)
|
||||
{
|
||||
AZ_Error("AssetBundler", false, "Selected index (%i, %i) is out of range.", row, col);
|
||||
return {};
|
||||
}
|
||||
|
||||
return m_fileListKeys.at(row);
|
||||
}
|
||||
|
||||
const AZStd::vector<AZStd::string>& AssetBundlerAbstractFileTableModel::GetAllFileKeys() const
|
||||
{
|
||||
return m_fileListKeys;
|
||||
}
|
||||
|
||||
int AssetBundlerAbstractFileTableModel::GetIndexRowByKey(const AZStd::string& key) const
|
||||
{
|
||||
auto it = AZStd::find(m_fileListKeys.begin(), m_fileListKeys.end(), key);
|
||||
return it == m_fileListKeys.end() ? -1 : static_cast<int>(AZStd::distance(m_fileListKeys.begin(), it));
|
||||
}
|
||||
|
||||
void AssetBundlerAbstractFileTableModel::AddFileKey(const AZStd::string& key)
|
||||
{
|
||||
if (AZStd::find(m_fileListKeys.begin(), m_fileListKeys.end(), key) != m_fileListKeys.end())
|
||||
{
|
||||
// Key already exists. This could happen when we update existing entires.
|
||||
return;
|
||||
}
|
||||
|
||||
beginInsertRows(QModelIndex(), rowCount(), rowCount());
|
||||
m_fileListKeys.push_back(key);
|
||||
endInsertRows();
|
||||
}
|
||||
|
||||
bool AssetBundlerAbstractFileTableModel::RemoveFileKey(const QModelIndex& index)
|
||||
{
|
||||
AZStd::string key = GetFileKey(index);
|
||||
if (key.empty())
|
||||
{
|
||||
// Error has already been thrown
|
||||
return false;
|
||||
}
|
||||
|
||||
int row = index.row();
|
||||
beginRemoveRows(QModelIndex(), row, row);
|
||||
|
||||
m_fileListKeys.erase(m_fileListKeys.begin() + row);
|
||||
m_keysWithUnsavedChanges.erase(key);
|
||||
|
||||
endRemoveRows();
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool AssetBundlerAbstractFileTableModel::DeleteFileByKey(const AZStd::string& key)
|
||||
{
|
||||
int indexRow = GetIndexRowByKey(key);
|
||||
if (indexRow >= 0)
|
||||
{
|
||||
return DeleteFile(index(indexRow, 0));
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
} // namespace AssetBundler
|
||||
@@ -0,0 +1,111 @@
|
||||
/*
|
||||
* 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.
|
||||
*
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <AzCore/std/containers/unordered_set.h>
|
||||
#include <AzCore/std/containers/vector.h>
|
||||
#include <AzCore/std/smart_ptr/unique_ptr.h>
|
||||
#include <AzCore/std/string/string.h>
|
||||
|
||||
#include <AzCore/Outcome/Outcome.h>
|
||||
#include <AzFramework/Platform/PlatformDefaults.h>
|
||||
|
||||
#include <QAbstractTableModel>
|
||||
#include <QModelIndex>
|
||||
#include <QSet>
|
||||
#include <QString>
|
||||
|
||||
|
||||
namespace AssetBundler
|
||||
{
|
||||
|
||||
extern const char* DateTimeFormat;
|
||||
|
||||
//! Provides an abstract model that can be subclassed to create table models used to store information about files found on-disk.
|
||||
class AssetBundlerAbstractFileTableModel
|
||||
: public QAbstractTableModel
|
||||
{
|
||||
public:
|
||||
|
||||
enum DataRoles
|
||||
{
|
||||
SortRole = Qt::UserRole + 1,
|
||||
};
|
||||
|
||||
explicit AssetBundlerAbstractFileTableModel(QObject* parent = nullptr);
|
||||
virtual ~AssetBundlerAbstractFileTableModel() {}
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////
|
||||
// Pure virtual functions
|
||||
virtual AZStd::vector<AZStd::string> CreateNewFiles(const AZStd::string& absoluteFilePath, const AzFramework::PlatformFlags& platforms, const QString& project = QString()) = 0;
|
||||
virtual bool DeleteFile(const QModelIndex& index) = 0;
|
||||
virtual void LoadFile(const AZStd::string& absoluteFilePath, const AZStd::string& projectName = "", bool isDefaultFile = false) = 0;
|
||||
virtual bool WriteToDisk(const AZStd::string& key) = 0;
|
||||
|
||||
//! Returns the absolute path of the file at the given index on success, returns an empty string on failure.
|
||||
virtual AZStd::string GetFileAbsolutePath(const QModelIndex& index) const = 0;
|
||||
|
||||
virtual int GetFileNameColumnIndex() const = 0;
|
||||
virtual int GetTimeStampColumnIndex() const = 0;
|
||||
//////////////////////////////////////////////////////////////////////////
|
||||
|
||||
//! Reload all the data based on the watched folders and files
|
||||
virtual void Reload(const char* fileExtension, const QSet<QString>& watchedFolders, const QSet<QString>& watchedFiles = QSet<QString>(), const AZStd::unordered_map<AZStd::string, AZStd::string>& pathToProjectNameMap = AZStd::unordered_map<AZStd::string, AZStd::string>());
|
||||
|
||||
virtual void ReloadFiles(const AZStd::vector<AZStd::string>& absoluteFilePathList, AZStd::unordered_map<AZStd::string, AZStd::string> pathToProjectNameMap = AZStd::unordered_map<AZStd::string, AZStd::string>());
|
||||
|
||||
bool Save(const QModelIndex& selectedIndex);
|
||||
|
||||
bool SaveAll();
|
||||
|
||||
bool HasUnsavedChanges() const;
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////
|
||||
// QAbstractTableModel overrides
|
||||
int rowCount(const QModelIndex& parent = QModelIndex()) const override;
|
||||
//////////////////////////////////////////////////////////////////////////
|
||||
|
||||
protected:
|
||||
//! Verifies input index is in range and returns the associated key.
|
||||
//! Throws an error and returns an empty string if the input index is out of range.
|
||||
AZStd::string GetFileKey(const QModelIndex& index) const;
|
||||
|
||||
//! Returns an ordered list of every file key in the model.
|
||||
//! If a proxy model is not used, the order of this list will also be the display order.
|
||||
const AZStd::vector<AZStd::string>& GetAllFileKeys() const;
|
||||
|
||||
//! Get the index row if the file info is stored in the model
|
||||
//! Returns -1 if the file key doesn't exist.
|
||||
int GetIndexRowByKey(const AZStd::string& key) const;
|
||||
|
||||
//! Adds input key to the end of the list of all keys and notifies the view that a row has been added.
|
||||
//! When subclassing, instantiate all data associated with this key so the view can update properly.
|
||||
void AddFileKey(const AZStd::string& key);
|
||||
|
||||
//! Verifies input index, signals to the view that rows will be removed, and removes the key found at the input index.
|
||||
//! When subclassing, be sure to remove all data associated with the key at this index before calling this function.
|
||||
//! Returns true if the index is successfully removed, and false on failure
|
||||
bool RemoveFileKey(const QModelIndex& index);
|
||||
|
||||
//! Delete a file from the disk and remove it from the model by its key
|
||||
bool DeleteFileByKey(const AZStd::string& key);
|
||||
|
||||
AZStd::unordered_set<AZStd::string> m_keysWithUnsavedChanges;
|
||||
|
||||
private:
|
||||
//! When subclassing: store file information in a map, and add the keys to this vector.
|
||||
//! Provides a 1:1 mapping between a QModelIndex::row value and a key.
|
||||
AZStd::vector<AZStd::string> m_fileListKeys;
|
||||
};
|
||||
|
||||
} // namespace AssetBundler
|
||||
@@ -0,0 +1,62 @@
|
||||
/*
|
||||
* 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 "AssetBundlerFileTableFilterModel.h"
|
||||
|
||||
#include <source/models/AssetBundlerAbstractFileTableModel.h>
|
||||
|
||||
#include <QDateTime>
|
||||
|
||||
namespace AssetBundler
|
||||
{
|
||||
AssetBundlerFileTableFilterModel::AssetBundlerFileTableFilterModel(QObject* parent, int displayNameCol, int dateTimeCol)
|
||||
: QSortFilterProxyModel(parent)
|
||||
, m_displayNameCol(displayNameCol)
|
||||
, m_dateTimeCol(dateTimeCol)
|
||||
{
|
||||
}
|
||||
|
||||
void AssetBundlerFileTableFilterModel::FilterChanged(const QString& newFilter)
|
||||
{
|
||||
setFilterRegExp(newFilter.toLower());
|
||||
invalidateFilter();
|
||||
}
|
||||
|
||||
bool AssetBundlerFileTableFilterModel::filterAcceptsRow(int sourceRow, const QModelIndex& sourceParent) const
|
||||
{
|
||||
// Override the default implemention since we want to define custom rules here
|
||||
QModelIndex index = sourceModel()->index(sourceRow, m_displayNameCol, sourceParent);
|
||||
QRegExp filter(filterRegExp());
|
||||
|
||||
return sourceModel()->data(index).toString().toLower().contains(filter);
|
||||
}
|
||||
|
||||
bool AssetBundlerFileTableFilterModel::lessThan(const QModelIndex& left, const QModelIndex& right) const
|
||||
{
|
||||
// Any column displaying a DateTime string needs to be compared as a DateTime object to ensure
|
||||
// proper sorting
|
||||
if (left.column() != m_dateTimeCol || right.column() != m_dateTimeCol)
|
||||
{
|
||||
return QSortFilterProxyModel::lessThan(left, right);
|
||||
}
|
||||
|
||||
QVariant leftTime = sourceModel()->data(left, AssetBundlerAbstractFileTableModel::SortRole);
|
||||
QVariant rightTime = sourceModel()->data(right, AssetBundlerAbstractFileTableModel::SortRole);
|
||||
|
||||
if (leftTime.type() != QVariant::DateTime || rightTime.type() != QVariant::DateTime)
|
||||
{
|
||||
return QSortFilterProxyModel::lessThan(left, right);
|
||||
}
|
||||
|
||||
return leftTime.toDateTime() < rightTime.toDateTime();
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,34 @@
|
||||
/*
|
||||
* 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.
|
||||
*
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <QSortFilterProxyModel>
|
||||
|
||||
namespace AssetBundler
|
||||
{
|
||||
class AssetBundlerFileTableFilterModel
|
||||
: public QSortFilterProxyModel
|
||||
{
|
||||
public:
|
||||
AssetBundlerFileTableFilterModel(QObject* parent, int displayNameCol, int dateTimeCol = -1);
|
||||
|
||||
void FilterChanged(const QString& newFilter);
|
||||
|
||||
protected:
|
||||
bool filterAcceptsRow(int sourceRow, const QModelIndex& sourceParent) const override;
|
||||
bool lessThan(const QModelIndex& left, const QModelIndex& right) const override;
|
||||
|
||||
int m_displayNameCol = 0;
|
||||
int m_dateTimeCol = -1;
|
||||
};
|
||||
}
|
||||
@@ -0,0 +1,251 @@
|
||||
/*
|
||||
* 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 <source/models/AssetListFileTableModel.h>
|
||||
#include <source/models/AssetListTableModel.h>
|
||||
|
||||
#include <source/utils/utils.h>
|
||||
|
||||
#include <AzCore/Outcome/Outcome.h>
|
||||
#include <AzFramework/IO/LocalFileIO.h>
|
||||
#include <AzFramework/Platform/PlatformDefaults.h>
|
||||
#include <AzFramework/StringFunc/StringFunc.h>
|
||||
#include <AzToolsFramework/Asset/AssetBundler.h>
|
||||
|
||||
#include <QFileInfo>
|
||||
#include <QFont>
|
||||
|
||||
namespace AssetBundler
|
||||
{
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
// AssetListFileInfo
|
||||
//////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
AssetListFileInfo::AssetListFileInfo(const AZStd::string& absolutePath, const QString& fileName, const AZStd::string& platform)
|
||||
: m_absolutePath(absolutePath)
|
||||
, m_fileName(fileName)
|
||||
, m_platform(QString(platform.c_str()))
|
||||
{
|
||||
AzFramework::StringFunc::Path::Normalize(m_absolutePath);
|
||||
|
||||
// Modification time will either give us the time the file was last overwritten
|
||||
// (or the time it was created if it has never been overwritten)
|
||||
QFileInfo fileInfo(m_absolutePath.c_str());
|
||||
m_fileCreationTime = fileInfo.fileTime(QFileDevice::FileModificationTime);
|
||||
|
||||
// Load the contents of the asset list file into memory
|
||||
m_assetListModel.reset(new AssetListTableModel(nullptr, absolutePath, platform));
|
||||
}
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
// AssetListFileTableModel
|
||||
//////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
AssetListFileTableModel::AssetListFileTableModel()
|
||||
: AssetBundlerAbstractFileTableModel()
|
||||
{
|
||||
}
|
||||
|
||||
QSharedPointer<AssetListTableModel> AssetListFileTableModel::GetAssetListFileContents(const QModelIndex& index)
|
||||
{
|
||||
auto assetListFileInfoOutcome = GetAssetFileInfo(index);
|
||||
if (!assetListFileInfoOutcome.IsSuccess())
|
||||
{
|
||||
return QSharedPointer<AssetListTableModel>();
|
||||
}
|
||||
|
||||
return assetListFileInfoOutcome.GetValue()->m_assetListModel;
|
||||
}
|
||||
|
||||
bool AssetListFileTableModel::DeleteFile(const QModelIndex& index)
|
||||
{
|
||||
auto assetFileInfoOutcome = GetAssetFileInfo(index);
|
||||
if (!assetFileInfoOutcome.IsSuccess())
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
AZStd::string key = AssetBundler::GenerateKeyFromAbsolutePath(assetFileInfoOutcome.GetValue()->m_absolutePath);
|
||||
if (m_assetListFileInfoMap.find(key) == m_assetListFileInfoMap.end())
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
AssetListFileInfoPtr assetFileInfo = m_assetListFileInfoMap[key];
|
||||
|
||||
// Remove file from disk
|
||||
const char* absolutePath = assetFileInfo->m_absolutePath.c_str();
|
||||
if (AZ::IO::FileIOBase::GetInstance()->Exists(absolutePath))
|
||||
{
|
||||
if (AZ::IO::FileIOBase::GetInstance()->IsReadOnly(absolutePath))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
auto deleteResult = AZ::IO::FileIOBase::GetInstance()->Remove(absolutePath);
|
||||
if (!deleteResult)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
// Remove file from model
|
||||
m_assetListFileInfoMap.erase(key);
|
||||
RemoveFileKey(index);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
void AssetListFileTableModel::LoadFile(const AZStd::string& absoluteFilePath, const AZStd::string& /*projectName*/, bool /*isDefaultFile*/)
|
||||
{
|
||||
AZStd::string fullFileName;
|
||||
AzFramework::StringFunc::Path::GetFullFileName(absoluteFilePath.c_str(), fullFileName);
|
||||
|
||||
// Get the file name without the platform for display purposes
|
||||
AZStd::string baseFileName;
|
||||
AZStd::string platformIdentifier;
|
||||
AzToolsFramework::SplitFilename(fullFileName, baseFileName, platformIdentifier);
|
||||
|
||||
// Read the AssetListFile into memory and store it
|
||||
AZStd::string key = AssetBundler::GenerateKeyFromAbsolutePath(absoluteFilePath);
|
||||
m_assetListFileInfoMap[key].reset(new AssetListFileInfo(absoluteFilePath, QString(baseFileName.c_str()), platformIdentifier));
|
||||
AddFileKey(key);
|
||||
}
|
||||
|
||||
bool AssetListFileTableModel::WriteToDisk(const AZStd::string& /*key*/)
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
AZStd::string AssetListFileTableModel::GetFileAbsolutePath(const QModelIndex& index) const
|
||||
{
|
||||
auto assetFileInfoOutcome = GetAssetFileInfo(index);
|
||||
if (!assetFileInfoOutcome.IsSuccess())
|
||||
{
|
||||
// Error has already been thrown
|
||||
return AZStd::string();
|
||||
}
|
||||
return assetFileInfoOutcome.GetValue()->m_absolutePath;
|
||||
}
|
||||
|
||||
int AssetListFileTableModel::GetFileNameColumnIndex() const
|
||||
{
|
||||
return Column::ColumnFileName;
|
||||
}
|
||||
|
||||
int AssetListFileTableModel::GetTimeStampColumnIndex() const
|
||||
{
|
||||
return Column::ColumnFileCreationTime;
|
||||
}
|
||||
|
||||
int AssetListFileTableModel::columnCount(const QModelIndex& parent) const
|
||||
{
|
||||
return parent.isValid() ? 0 : Column::Max;
|
||||
}
|
||||
|
||||
QVariant AssetListFileTableModel::headerData(int section, Qt::Orientation orientation, int role) const
|
||||
{
|
||||
if (role == Qt::DisplayRole && orientation == Qt::Horizontal)
|
||||
{
|
||||
switch (section)
|
||||
{
|
||||
case Column::ColumnFileName:
|
||||
return QString(tr("Asset List File"));
|
||||
case Column::ColumnPlatform:
|
||||
return QString(tr("Platform"));
|
||||
case Column::ColumnFileCreationTime:
|
||||
return QString(tr("Creation Time"));
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
return QVariant();
|
||||
}
|
||||
|
||||
QVariant AssetListFileTableModel::data(const QModelIndex& index, int role) const
|
||||
{
|
||||
auto assetListFileInfoOutcome = GetAssetFileInfo(index);
|
||||
if (!assetListFileInfoOutcome.IsSuccess())
|
||||
{
|
||||
return QVariant();
|
||||
}
|
||||
|
||||
int col = index.column();
|
||||
|
||||
switch (role)
|
||||
{
|
||||
case Qt::DisplayRole:
|
||||
[[fallthrough]];
|
||||
case SortRole:
|
||||
{
|
||||
if (col == Column::ColumnFileName)
|
||||
{
|
||||
return assetListFileInfoOutcome.GetValue()->m_fileName;
|
||||
}
|
||||
else if (col == Column::ColumnPlatform)
|
||||
{
|
||||
return assetListFileInfoOutcome.GetValue()->m_platform;
|
||||
}
|
||||
else if (col == Column::ColumnFileCreationTime)
|
||||
{
|
||||
if (role == SortRole)
|
||||
{
|
||||
return assetListFileInfoOutcome.GetValue()->m_fileCreationTime;
|
||||
}
|
||||
else
|
||||
{
|
||||
return assetListFileInfoOutcome.GetValue()->m_fileCreationTime.toString(DateTimeFormat);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
// Returning an empty QString will ensure the checkboxes do not have any text displayed next to them
|
||||
return QString();
|
||||
}
|
||||
}
|
||||
case Qt::FontRole:
|
||||
{
|
||||
if (col == Column::ColumnFileName)
|
||||
{
|
||||
QFont boldFont;
|
||||
boldFont.setBold(true);
|
||||
return boldFont;
|
||||
}
|
||||
}
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
return QVariant();
|
||||
}
|
||||
|
||||
AZ::Outcome<AssetListFileInfoPtr, void> AssetListFileTableModel::GetAssetFileInfo(const QModelIndex& index) const
|
||||
{
|
||||
AZStd::string key = GetFileKey(index);
|
||||
if (key.empty())
|
||||
{
|
||||
// Error has already been thrown
|
||||
return AZ::Failure();
|
||||
}
|
||||
|
||||
if (m_assetListFileInfoMap.find(key) != m_assetListFileInfoMap.end())
|
||||
{
|
||||
return AZ::Success(m_assetListFileInfoMap.at(key));
|
||||
}
|
||||
else
|
||||
{
|
||||
AZ_Error(AssetBundler::AppWindowName, false, "Cannot find Asset List File Info");
|
||||
return AZ::Failure();
|
||||
}
|
||||
}
|
||||
|
||||
} // namespace AssetBundler
|
||||
@@ -0,0 +1,88 @@
|
||||
/*
|
||||
* 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.
|
||||
*
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <source/models/AssetBundlerAbstractFileTableModel.h>
|
||||
|
||||
#include <QDateTime>
|
||||
#include <QSharedPointer>
|
||||
|
||||
namespace AssetBundler
|
||||
{
|
||||
class AssetListTableModel;
|
||||
|
||||
struct AssetListFileInfo
|
||||
{
|
||||
/**
|
||||
* Stores information about an Asset List File on disk.
|
||||
*
|
||||
* @param absolutePath The absolute path of the Asset List File
|
||||
* @param fileName The name of the Asset List File. This does not include the platform ID
|
||||
* @param platform The platform for the Asset List File
|
||||
*/
|
||||
AssetListFileInfo(const AZStd::string& absolutePath, const QString& fileName, const AZStd::string& platform);
|
||||
|
||||
AZStd::string m_absolutePath;
|
||||
QDateTime m_fileCreationTime;
|
||||
/// Use QString for display purpose. This can help to avoid losts of string conversion
|
||||
QString m_fileName;
|
||||
QString m_platform;
|
||||
|
||||
QSharedPointer<AssetListTableModel> m_assetListModel;
|
||||
};
|
||||
|
||||
using AssetListFileInfoPtr = AZStd::shared_ptr<AssetListFileInfo>;
|
||||
/// Stores AssetListFileInfo, using the absolute path (without the drive letter) of the Asset List file as the key
|
||||
using AssetListFileInfoMap = AZStd::unordered_map<AZStd::string, AssetListFileInfoPtr>;
|
||||
|
||||
class AssetListFileTableModel
|
||||
: public AssetBundlerAbstractFileTableModel
|
||||
{
|
||||
public:
|
||||
explicit AssetListFileTableModel();
|
||||
virtual ~AssetListFileTableModel() {}
|
||||
|
||||
QSharedPointer<AssetListTableModel> GetAssetListFileContents(const QModelIndex& index);
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////
|
||||
// AssetBundlerAbstractFileTableModel overrides
|
||||
AZStd::vector<AZStd::string> CreateNewFiles(const AZStd::string& /*absoluteFilePath*/, const AzFramework::PlatformFlags& /*platforms*/, const QString& /*project*/) override { return {}; }
|
||||
bool DeleteFile(const QModelIndex& index) override;
|
||||
void LoadFile(const AZStd::string& absoluteFilePath, const AZStd::string& projectName = "", bool isDefaultFile = false) override;
|
||||
bool WriteToDisk(const AZStd::string& key) override;
|
||||
AZStd::string GetFileAbsolutePath(const QModelIndex& index) const override;
|
||||
int GetFileNameColumnIndex() const override;
|
||||
int GetTimeStampColumnIndex() const override;
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////
|
||||
// QAbstractListModel overrides
|
||||
int columnCount(const QModelIndex& parent = QModelIndex()) const override;
|
||||
QVariant headerData(int section, Qt::Orientation orientation, int role) const override;
|
||||
QVariant data(const QModelIndex& index, int role) const override;
|
||||
//////////////////////////////////////////////////////////////////////////
|
||||
|
||||
enum Column
|
||||
{
|
||||
ColumnFileName,
|
||||
ColumnPlatform,
|
||||
ColumnFileCreationTime,
|
||||
Max
|
||||
};
|
||||
|
||||
private:
|
||||
AZ::Outcome<AssetListFileInfoPtr, void> GetAssetFileInfo(const QModelIndex& index) const;
|
||||
|
||||
AssetListFileInfoMap m_assetListFileInfoMap;
|
||||
};
|
||||
|
||||
} // namespace AssetBundler
|
||||
@@ -0,0 +1,129 @@
|
||||
/*
|
||||
* 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 <source/models/AssetListTableModel.h>
|
||||
|
||||
#include <source/utils/utils.h>
|
||||
|
||||
#include <AzFramework/StringFunc/StringFunc.h>
|
||||
|
||||
namespace AssetBundler
|
||||
{
|
||||
//////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
// AssetListTableModel
|
||||
//////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
AssetListTableModel::AssetListTableModel(QObject* parent, const AZStd::string& absolutePath, const AZStd::string& platform)
|
||||
: QAbstractTableModel(parent)
|
||||
{
|
||||
m_seedListManager.reset(new AzToolsFramework::AssetSeedManager());
|
||||
|
||||
if (absolutePath.empty() || platform.empty())
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
AZ::Outcome<AzToolsFramework::AssetFileInfoList, AZStd::string> outcome = m_seedListManager->LoadAssetFileInfo(absolutePath);
|
||||
if (!outcome.IsSuccess())
|
||||
{
|
||||
AZ_Error(AssetBundler::AppWindowName, false, "Failed to load the asset file info for %s", absolutePath.c_str());
|
||||
return;
|
||||
}
|
||||
|
||||
m_assetFileInfoList = outcome.TakeValue();
|
||||
m_platformId = static_cast<AzFramework::PlatformId>(AzFramework::PlatformHelper::GetPlatformIndexFromName(platform.c_str()));
|
||||
}
|
||||
|
||||
int AssetListTableModel::rowCount(const QModelIndex& parent) const
|
||||
{
|
||||
return parent.isValid() ? 0 : static_cast<int>(m_assetFileInfoList.m_fileInfoList.size());
|
||||
}
|
||||
|
||||
int AssetListTableModel::columnCount(const QModelIndex& parent) const
|
||||
{
|
||||
return parent.isValid() ? 0 : Column::Max;
|
||||
}
|
||||
|
||||
QVariant AssetListTableModel::headerData(int section, Qt::Orientation orientation, int role) const
|
||||
{
|
||||
if (role == Qt::DisplayRole && orientation == Qt::Horizontal)
|
||||
{
|
||||
switch (section)
|
||||
{
|
||||
case Column::ColumnAssetName:
|
||||
return QString("Asset Name");
|
||||
case Column::ColumnRelativePath:
|
||||
return QString("Relative Path");
|
||||
case Column::ColumnAssetId:
|
||||
return QString("Asset ID");
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
return QVariant();
|
||||
}
|
||||
|
||||
QVariant AssetListTableModel::data(const QModelIndex& index, int role) const
|
||||
{
|
||||
auto assetFileInfoOutcome = GetAssetFileInfo(index);
|
||||
if (!assetFileInfoOutcome.IsSuccess())
|
||||
{
|
||||
return QVariant();
|
||||
}
|
||||
|
||||
switch (role)
|
||||
{
|
||||
case Qt::DisplayRole:
|
||||
{
|
||||
switch (index.column())
|
||||
{
|
||||
case Column::ColumnAssetName:
|
||||
{
|
||||
AZStd::string fileName = assetFileInfoOutcome.GetValue().m_assetRelativePath;
|
||||
AzFramework::StringFunc::Path::GetFullFileName(fileName.c_str(), fileName);
|
||||
|
||||
return fileName.c_str();
|
||||
}
|
||||
case Column::ColumnRelativePath:
|
||||
{
|
||||
return assetFileInfoOutcome.GetValue().m_assetRelativePath.c_str();
|
||||
}
|
||||
case Column::ColumnAssetId:
|
||||
{
|
||||
AZStd::string assetIdStr;
|
||||
assetFileInfoOutcome.GetValue().m_assetId.ToString(assetIdStr);
|
||||
|
||||
return assetIdStr.c_str();
|
||||
}
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
return QVariant();
|
||||
}
|
||||
|
||||
AZ::Outcome<AzToolsFramework::AssetFileInfo&, AZStd::string> AssetListTableModel::GetAssetFileInfo(const QModelIndex& index) const
|
||||
{
|
||||
int row = index.row();
|
||||
int col = index.column();
|
||||
if (row >= rowCount() || row < 0 || col >= columnCount() || col < 0)
|
||||
{
|
||||
return AZ::Failure(AZStd::string::format("Selected index (%i, %i) is out of range", row, col));
|
||||
}
|
||||
|
||||
return AZ::Success(m_assetFileInfoList.m_fileInfoList.at(row));
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,54 @@
|
||||
/*
|
||||
* 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.
|
||||
*
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <AzToolsFramework/Asset/AssetSeedManager.h>
|
||||
#include <AzFramework/Platform/PlatformDefaults.h>
|
||||
|
||||
#include <QAbstractTableModel>
|
||||
|
||||
namespace AssetBundler
|
||||
{
|
||||
class AssetListTableModel
|
||||
: public QAbstractTableModel
|
||||
{
|
||||
public:
|
||||
explicit AssetListTableModel(QObject* parent = nullptr, const AZStd::string& absolutePath = AZStd::string(), const AZStd::string& platform = "");
|
||||
virtual ~AssetListTableModel() {}
|
||||
|
||||
AZStd::shared_ptr<AzToolsFramework::AssetSeedManager> GetSeedListManager() { return m_seedListManager; }
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////
|
||||
// QAbstractListModel overrides
|
||||
int rowCount(const QModelIndex& parent = QModelIndex()) const override;
|
||||
int columnCount(const QModelIndex& parent = QModelIndex()) const override;
|
||||
QVariant headerData(int section, Qt::Orientation orientation, int role) const override;
|
||||
QVariant data(const QModelIndex& index, int role) const override;
|
||||
//////////////////////////////////////////////////////////////////////////
|
||||
|
||||
enum Column
|
||||
{
|
||||
ColumnAssetName,
|
||||
ColumnRelativePath,
|
||||
ColumnAssetId,
|
||||
Max
|
||||
};
|
||||
|
||||
private:
|
||||
AZ::Outcome<AzToolsFramework::AssetFileInfo&, AZStd::string> GetAssetFileInfo(const QModelIndex& index) const;
|
||||
|
||||
AZStd::shared_ptr<AzToolsFramework::AssetSeedManager> m_seedListManager;
|
||||
AzToolsFramework::AssetFileInfoList m_assetFileInfoList;
|
||||
AzFramework::PlatformId m_platformId;
|
||||
};
|
||||
}
|
||||
@@ -0,0 +1,236 @@
|
||||
/*
|
||||
* 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 <source/models/BundleFileListModel.h>
|
||||
|
||||
#include <AzFramework/IO/LocalFileIO.h>
|
||||
#include <AzToolsFramework/AssetBundle/AssetBundleComponent.h>
|
||||
|
||||
#include <source/utils/utils.h>
|
||||
|
||||
#include <QFileInfo>
|
||||
|
||||
|
||||
namespace AssetBundler
|
||||
{
|
||||
BundleFileInfo::BundleFileInfo(const AZStd::string& absolutePath)
|
||||
: m_absolutePath(absolutePath)
|
||||
, m_compressedSize(0u)
|
||||
{
|
||||
AzFramework::StringFunc::Path::Normalize(m_absolutePath);
|
||||
|
||||
AZStd::string fileNameStr;
|
||||
if (AzFramework::StringFunc::Path::GetFileName(m_absolutePath.c_str(), fileNameStr))
|
||||
{
|
||||
m_fileName = QString(fileNameStr.c_str());
|
||||
}
|
||||
else
|
||||
{
|
||||
AZ_Error("AssetBundler", false, "Failed to get file name from %s", m_absolutePath.c_str());
|
||||
}
|
||||
|
||||
// Modification time will either give us the time the file was last overwritten
|
||||
// (or the time it was created if it has never been overwritten)
|
||||
QFileInfo fileInfo(m_absolutePath.c_str());
|
||||
m_fileCreationTime = fileInfo.fileTime(QFileDevice::FileModificationTime);
|
||||
}
|
||||
|
||||
BundleFileListModel::BundleFileListModel()
|
||||
: AssetBundlerAbstractFileTableModel()
|
||||
{
|
||||
}
|
||||
|
||||
bool BundleFileListModel::DeleteFile(const QModelIndex& index)
|
||||
{
|
||||
AZStd::string fileKey = GetFileKey(index);
|
||||
if (fileKey.empty())
|
||||
{
|
||||
// Error has already been thrown
|
||||
return false;
|
||||
}
|
||||
|
||||
auto bundleFileInfoIt = m_bundleFileInfoMap.find(fileKey);
|
||||
if (bundleFileInfoIt == m_bundleFileInfoMap.end())
|
||||
{
|
||||
AZ_Error(AssetBundler::AppWindowName, false, "Unable to find Bundle Info with key ( %s )", fileKey.c_str());
|
||||
return false;
|
||||
}
|
||||
|
||||
BundleFileInfoPtr bundleFileInfo = bundleFileInfoIt->second;
|
||||
|
||||
// Remove file from disk
|
||||
const char* absolutePath = bundleFileInfo->m_absolutePath.c_str();
|
||||
if (AZ::IO::FileIOBase::GetInstance()->Exists(absolutePath))
|
||||
{
|
||||
if (AZ::IO::FileIOBase::GetInstance()->IsReadOnly(absolutePath))
|
||||
{
|
||||
AZ_Error(AssetBundler::AppWindowName, false, "File (%s) is Read-Only. Please check your version control and try again.", absolutePath);
|
||||
return false;
|
||||
}
|
||||
|
||||
auto deleteResult = AZ::IO::FileIOBase::GetInstance()->Remove(absolutePath);
|
||||
if (!deleteResult)
|
||||
{
|
||||
AZ_Error(AssetBundler::AppWindowName, false, "Unable to delete: %s", absolutePath);
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
// Remove file from Model
|
||||
m_bundleFileInfoMap.erase(fileKey);
|
||||
RemoveFileKey(index);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
int BundleFileListModel::columnCount(const QModelIndex& parent) const
|
||||
{
|
||||
return parent.isValid() ? 0 : Column::Max;
|
||||
}
|
||||
|
||||
QVariant BundleFileListModel::headerData(int section, Qt::Orientation orientation, int role) const
|
||||
{
|
||||
if (role == Qt::DisplayRole && orientation == Qt::Horizontal)
|
||||
{
|
||||
switch (section)
|
||||
{
|
||||
case Column::ColumnFileName:
|
||||
return QString(tr("Name"));
|
||||
case Column::ColumnFileCreationTime:
|
||||
return QString(tr("Creation Time"));
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
return QVariant();
|
||||
}
|
||||
|
||||
QVariant BundleFileListModel::data(const QModelIndex& index, int role) const
|
||||
{
|
||||
auto bundleInfoOutcome = GetBundleInfo(index);
|
||||
if (!bundleInfoOutcome.IsSuccess())
|
||||
{
|
||||
return QVariant();
|
||||
}
|
||||
|
||||
int col = index.column();
|
||||
|
||||
switch (role)
|
||||
{
|
||||
case Qt::DisplayRole:
|
||||
[[fallthrough]];
|
||||
case SortRole:
|
||||
{
|
||||
if (col == Column::ColumnFileName)
|
||||
{
|
||||
return bundleInfoOutcome.GetValue()->m_fileName;
|
||||
}
|
||||
else if (col == Column::ColumnFileCreationTime)
|
||||
{
|
||||
if (role == SortRole)
|
||||
{
|
||||
return bundleInfoOutcome.GetValue()->m_fileCreationTime;
|
||||
}
|
||||
else
|
||||
{
|
||||
return bundleInfoOutcome.GetValue()->m_fileCreationTime.toString(DateTimeFormat);
|
||||
}
|
||||
}
|
||||
}
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
return QVariant();
|
||||
}
|
||||
|
||||
AZStd::string BundleFileListModel::GetFileAbsolutePath(const QModelIndex& index) const
|
||||
{
|
||||
AZStd::string key = GetFileKey(index);
|
||||
if (key.empty())
|
||||
{
|
||||
// Error has already been thrown
|
||||
return key;
|
||||
}
|
||||
|
||||
return m_bundleFileInfoMap.at(key)->m_absolutePath;
|
||||
}
|
||||
|
||||
int BundleFileListModel::GetFileNameColumnIndex() const
|
||||
{
|
||||
return Column::ColumnFileName;
|
||||
}
|
||||
|
||||
int BundleFileListModel::GetTimeStampColumnIndex() const
|
||||
{
|
||||
return Column::ColumnFileCreationTime;
|
||||
}
|
||||
|
||||
void BundleFileListModel::LoadFile(const AZStd::string& absoluteFilePath, const AZStd::string& /*projectName*/, bool /*isDefaultFile*/)
|
||||
{
|
||||
AZStd::string key = AssetBundler::GenerateKeyFromAbsolutePath(absoluteFilePath);
|
||||
|
||||
BundleFileInfo* newInfo = new BundleFileInfo(absoluteFilePath);
|
||||
|
||||
QFile bundleFile(absoluteFilePath.c_str());
|
||||
if (bundleFile.open(QIODevice::ReadOnly))
|
||||
{
|
||||
newInfo->m_compressedSize = bundleFile.size();
|
||||
bundleFile.close();
|
||||
}
|
||||
else
|
||||
{
|
||||
AZ_Error("AssetBundler", false, "Failed to open file at %s", absoluteFilePath.c_str());
|
||||
}
|
||||
|
||||
auto manifest = AzToolsFramework::AssetBundleComponent::GetManifestFromBundle(absoluteFilePath);
|
||||
if (manifest != nullptr)
|
||||
{
|
||||
for (auto& bundleName : manifest->GetDependentBundleNames())
|
||||
{
|
||||
newInfo->m_relatedBundles.push_back(bundleName.c_str());
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
AZ_Error("AssetBundler", false, "Failed to get manifest from bundle at %s", absoluteFilePath.c_str());
|
||||
}
|
||||
|
||||
m_bundleFileInfoMap[key].reset(newInfo);
|
||||
// Add it to the list that gets displayed by AssetBundlerAbstractFileTableModel. Make sure that
|
||||
// AddFileKey is called after m_bundleFileInfoMap is reset since the filterAcceptsRow funtion
|
||||
// of the filter model will be called when a new row is inserted and it could cause a crash
|
||||
// without valid data being set
|
||||
AddFileKey(key);
|
||||
}
|
||||
|
||||
AZ::Outcome<BundleFileInfoPtr, void> BundleFileListModel::GetBundleInfo(const QModelIndex& index) const
|
||||
{
|
||||
AZStd::string key = GetFileKey(index);
|
||||
if (key.empty())
|
||||
{
|
||||
// Error has already been thrown
|
||||
return AZ::Failure();
|
||||
}
|
||||
|
||||
if (m_bundleFileInfoMap.find(key) != m_bundleFileInfoMap.end())
|
||||
{
|
||||
return AZ::Success(m_bundleFileInfoMap.at(key));
|
||||
}
|
||||
else
|
||||
{
|
||||
AZ_Error(AssetBundler::AppWindowName, false, "Cannot find Bundle File Info");
|
||||
return AZ::Failure();
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,74 @@
|
||||
/*
|
||||
* 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.
|
||||
*
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <source/models/AssetBundlerAbstractFileTableModel.h>
|
||||
#include <AzFramework/StringFunc/StringFunc.h>
|
||||
|
||||
#include <AzToolsFramework/Asset/AssetBundler.h>
|
||||
|
||||
#include <QDateTime>
|
||||
|
||||
namespace AssetBundler
|
||||
{
|
||||
|
||||
struct BundleFileInfo
|
||||
{
|
||||
AZStd::string m_absolutePath;
|
||||
QString m_fileName;
|
||||
QDateTime m_fileCreationTime;
|
||||
AZ::u64 m_compressedSize;
|
||||
QStringList m_relatedBundles;
|
||||
|
||||
BundleFileInfo(const AZStd::string& absolutePath);
|
||||
};
|
||||
|
||||
using BundleFileInfoPtr = AZStd::shared_ptr<BundleFileInfo>;
|
||||
using BundleFileInfoMap = AZStd::unordered_map<AZStd::string, BundleFileInfoPtr>;
|
||||
|
||||
class BundleFileListModel
|
||||
: public AssetBundlerAbstractFileTableModel
|
||||
{
|
||||
public:
|
||||
explicit BundleFileListModel();
|
||||
virtual ~BundleFileListModel() {}
|
||||
|
||||
AZStd::vector<AZStd::string> CreateNewFiles(const AZStd::string& /*absoluteFilePath*/, const AzFramework::PlatformFlags& /*platforms*/, const QString& /*project*/) override { return {}; }
|
||||
bool DeleteFile(const QModelIndex& index) override;
|
||||
void LoadFile(const AZStd::string& absoluteFilePath, const AZStd::string& projectName = "", bool isDefaultFile = false) override;
|
||||
bool WriteToDisk(const AZStd::string& /*key*/) override { return true; }
|
||||
|
||||
AZStd::string GetFileAbsolutePath(const QModelIndex& index) const override;
|
||||
int GetFileNameColumnIndex() const override;
|
||||
int GetTimeStampColumnIndex() const override;
|
||||
|
||||
AZ::Outcome<BundleFileInfoPtr, void> GetBundleInfo(const QModelIndex& index) const;
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////
|
||||
// QAbstractTableModel overrides
|
||||
int columnCount(const QModelIndex& parent = QModelIndex()) const override;
|
||||
QVariant headerData(int section, Qt::Orientation orientation, int role) const override;
|
||||
QVariant data(const QModelIndex& index, int role) const override;
|
||||
//////////////////////////////////////////////////////////////////////////
|
||||
|
||||
enum Column
|
||||
{
|
||||
ColumnFileName,
|
||||
ColumnFileCreationTime,
|
||||
Max
|
||||
};
|
||||
|
||||
private:
|
||||
BundleFileInfoMap m_bundleFileInfoMap;
|
||||
};
|
||||
}
|
||||
@@ -0,0 +1,305 @@
|
||||
/*
|
||||
* 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 <source/models/RulesFileTableModel.h>
|
||||
|
||||
#include <AzCore/std/smart_ptr/shared_ptr.h>
|
||||
#include <AzCore/std/smart_ptr/make_shared.h>
|
||||
#include <AzFramework/IO/LocalFileIO.h>
|
||||
#include <AzFramework/StringFunc/StringFunc.h>
|
||||
|
||||
#include <QFileInfo>
|
||||
#include <QFont>
|
||||
|
||||
namespace AssetBundler
|
||||
{
|
||||
RulesFileInfo::RulesFileInfo(const AZStd::string& absolutePath, const QString& fileName, bool loadFromFile)
|
||||
: m_absolutePath(absolutePath)
|
||||
, m_fileName(fileName)
|
||||
{
|
||||
AzFramework::StringFunc::Path::Normalize(m_absolutePath);
|
||||
m_comparisonSteps = AZStd::make_shared<AzToolsFramework::AssetFileInfoListComparison>();
|
||||
|
||||
if (loadFromFile)
|
||||
{
|
||||
auto outcome = AzToolsFramework::AssetFileInfoListComparison::Load(m_absolutePath);
|
||||
if (!outcome.IsSuccess())
|
||||
{
|
||||
AZ_Error("AssetBundler", false, outcome.GetError().c_str());
|
||||
return;
|
||||
}
|
||||
m_comparisonSteps = AZStd::make_unique<AzToolsFramework::AssetFileInfoListComparison>(outcome.TakeValue());
|
||||
|
||||
QFileInfo fileInfo(m_absolutePath.c_str());
|
||||
m_fileModificationTime = fileInfo.fileTime(QFileDevice::FileModificationTime);
|
||||
}
|
||||
else
|
||||
{
|
||||
m_fileModificationTime = QDateTime::currentDateTime();
|
||||
}
|
||||
}
|
||||
|
||||
bool RulesFileInfo::SaveRulesFile()
|
||||
{
|
||||
if (!m_comparisonSteps->Save(m_absolutePath))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
m_hasUnsavedChanges = false;
|
||||
m_fileModificationTime = QDateTime::currentDateTime();
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
|
||||
RulesFileTableModel::RulesFileTableModel()
|
||||
: AssetBundlerAbstractFileTableModel()
|
||||
{
|
||||
}
|
||||
|
||||
AZStd::vector<AZStd::string> RulesFileTableModel::CreateNewFiles(const AZStd::string& absoluteFilePath, const AzFramework::PlatformFlags& /*platforms*/, const QString& /*project*/)
|
||||
{
|
||||
if (absoluteFilePath.empty())
|
||||
{
|
||||
AZ_Error(AssetBundler::AppWindowName, false, "Input file path is empty");
|
||||
return {};
|
||||
}
|
||||
|
||||
// Create a platform-specific file path
|
||||
if (AZ::IO::FileIOBase::GetInstance()->Exists(absoluteFilePath.c_str()))
|
||||
{
|
||||
AZ_Error(AssetBundler::AppWindowName, false, "Cannot Create New File: (%s) already exists", absoluteFilePath.c_str());
|
||||
return {};
|
||||
}
|
||||
|
||||
// Get the file name without the extension for display purposes
|
||||
AZStd::string fileName = absoluteFilePath;
|
||||
AzToolsFramework::RemovePlatformIdentifier(fileName);
|
||||
AzFramework::StringFunc::Path::GetFileName(fileName.c_str(), fileName);
|
||||
|
||||
// Create a Rules File and save it to disk
|
||||
AZStd::string key = AssetBundler::GenerateKeyFromAbsolutePath(absoluteFilePath);
|
||||
RulesFileInfoPtr newRulesFile = AZStd::make_shared<RulesFileInfo>(absoluteFilePath, QString(fileName.c_str()), false);
|
||||
|
||||
if (!newRulesFile->SaveRulesFile())
|
||||
{
|
||||
return {};
|
||||
}
|
||||
|
||||
// Add the new file to the model
|
||||
m_rulesFileInfoMap[key] = newRulesFile;
|
||||
AddFileKey(key);
|
||||
return { absoluteFilePath };
|
||||
}
|
||||
|
||||
bool RulesFileTableModel::DeleteFile(const QModelIndex& index)
|
||||
{
|
||||
AZStd::string key = GetFileKey(index);
|
||||
if (key.empty())
|
||||
{
|
||||
// Error has already been thrown
|
||||
return false;
|
||||
}
|
||||
|
||||
RulesFileInfoPtr rulesFileInfo = m_rulesFileInfoMap[key];
|
||||
|
||||
// Remove file from disk
|
||||
if (AZ::IO::FileIOBase::GetInstance()->IsReadOnly(rulesFileInfo->m_absolutePath.c_str()))
|
||||
{
|
||||
AZ_Error(AssetBundler::AppWindowName, false, "File (%s) is Read-Only. Please check your version control and try again.", rulesFileInfo->m_absolutePath.c_str());
|
||||
return false;
|
||||
}
|
||||
|
||||
auto deleteResult = AZ::IO::FileIOBase::GetInstance()->Remove(rulesFileInfo->m_absolutePath.c_str());
|
||||
if (!deleteResult)
|
||||
{
|
||||
AZ_Error(AssetBundler::AppWindowName, false, "Unable to delete: %s", rulesFileInfo->m_absolutePath.c_str());
|
||||
return false;
|
||||
}
|
||||
|
||||
// Remove file from model
|
||||
m_rulesFileInfoMap.erase(key);
|
||||
RemoveFileKey(index);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
void RulesFileTableModel::LoadFile(const AZStd::string& absoluteFilePath, const AZStd::string& /*projectName*/, bool /*isDefaultFile*/)
|
||||
{
|
||||
// Get the file name without the extension for display purposes
|
||||
AZStd::string fileName(absoluteFilePath);
|
||||
AzFramework::StringFunc::Path::GetFileName(fileName.c_str(), fileName);
|
||||
|
||||
// Read the Rules file into memory and store it
|
||||
AZStd::string key = AssetBundler::GenerateKeyFromAbsolutePath(absoluteFilePath);
|
||||
auto fileInfoIt = m_rulesFileInfoMap.find(key);
|
||||
if (fileInfoIt != m_rulesFileInfoMap.end() && fileInfoIt->second->m_hasUnsavedChanges)
|
||||
{
|
||||
AZ_Warning(AssetBundler::AppWindowName, false, "Rules File %s has unsaved changes and couldn't be reloaded", absoluteFilePath.c_str());
|
||||
return;
|
||||
}
|
||||
|
||||
m_rulesFileInfoMap[key] = AZStd::make_shared<RulesFileInfo>(absoluteFilePath, QString(fileName.c_str()), true);
|
||||
AddFileKey(key);
|
||||
}
|
||||
|
||||
bool RulesFileTableModel::WriteToDisk(const AZStd::string& key)
|
||||
{
|
||||
auto rulesFileIt = m_rulesFileInfoMap.find(key);
|
||||
return rulesFileIt != m_rulesFileInfoMap.end() && rulesFileIt->second->SaveRulesFile();
|
||||
}
|
||||
|
||||
AZStd::string RulesFileTableModel::GetFileAbsolutePath(const QModelIndex& index) const
|
||||
{
|
||||
RulesFileInfoPtr rulesFileInfo = GetRulesFileInfoPtr(index);
|
||||
if (!rulesFileInfo)
|
||||
{
|
||||
return AZStd::string();
|
||||
}
|
||||
|
||||
return rulesFileInfo->m_absolutePath;
|
||||
}
|
||||
|
||||
int RulesFileTableModel::GetFileNameColumnIndex() const
|
||||
{
|
||||
return Column::ColumnFileName;
|
||||
}
|
||||
|
||||
int RulesFileTableModel::GetTimeStampColumnIndex() const
|
||||
{
|
||||
return Column::ColumnFileModificationTime;
|
||||
}
|
||||
|
||||
AZStd::shared_ptr<AzToolsFramework::AssetFileInfoListComparison> RulesFileTableModel::GetComparisonSteps(const QModelIndex& index) const
|
||||
{
|
||||
RulesFileInfoPtr rulesFileInfo = GetRulesFileInfoPtr(index);
|
||||
if (!rulesFileInfo)
|
||||
{
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
return rulesFileInfo->m_comparisonSteps;
|
||||
}
|
||||
|
||||
bool RulesFileTableModel::MarkFileChanged(const QModelIndex& index)
|
||||
{
|
||||
AZStd::string key = GetFileKey(index);
|
||||
if (key.empty())
|
||||
{
|
||||
// Error has already been thrown
|
||||
return false;
|
||||
}
|
||||
|
||||
m_rulesFileInfoMap[key]->m_hasUnsavedChanges = true;
|
||||
|
||||
// Update display so the user knows there are unsaved changes
|
||||
m_keysWithUnsavedChanges.emplace(key);
|
||||
QModelIndex changedIndex = QAbstractTableModel::index(index.row(), Column::ColumnFileName);
|
||||
emit dataChanged(changedIndex, changedIndex, { Qt::DisplayRole, Qt::FontRole });
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
int RulesFileTableModel::columnCount(const QModelIndex& parent) const
|
||||
{
|
||||
return parent.isValid() ? 0 : Column::Max;
|
||||
}
|
||||
|
||||
QVariant RulesFileTableModel::headerData(int section, Qt::Orientation orientation, int role) const
|
||||
{
|
||||
if (role == Qt::DisplayRole && orientation == Qt::Horizontal)
|
||||
{
|
||||
switch (section)
|
||||
{
|
||||
case Column::ColumnFileName:
|
||||
return QString(tr("Name"));
|
||||
case Column::ColumnFileModificationTime:
|
||||
return QString(tr("Modification Time"));
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
return QVariant();
|
||||
}
|
||||
|
||||
QVariant RulesFileTableModel::data(const QModelIndex& index, int role) const
|
||||
{
|
||||
AZStd::string key = GetFileKey(index);
|
||||
if (key.empty())
|
||||
{
|
||||
return QVariant();
|
||||
}
|
||||
|
||||
RulesFileInfoPtr rulesFileInfo = m_rulesFileInfoMap.at(key);
|
||||
|
||||
int col = index.column();
|
||||
bool hasUnsavedChanges = rulesFileInfo->m_hasUnsavedChanges;
|
||||
|
||||
switch (role)
|
||||
{
|
||||
case Qt::DisplayRole:
|
||||
[[fallthrough]];
|
||||
case SortRole:
|
||||
{
|
||||
if (col == Column::ColumnFileName)
|
||||
{
|
||||
QString displayName = rulesFileInfo->m_fileName;
|
||||
if (hasUnsavedChanges)
|
||||
{
|
||||
displayName.append("*");
|
||||
}
|
||||
return displayName;
|
||||
}
|
||||
else if (col == Column::ColumnFileModificationTime)
|
||||
{
|
||||
if (role == SortRole)
|
||||
{
|
||||
return rulesFileInfo->m_fileModificationTime;
|
||||
}
|
||||
else
|
||||
{
|
||||
return rulesFileInfo->m_fileModificationTime.toString(DateTimeFormat);
|
||||
}
|
||||
}
|
||||
break;
|
||||
}
|
||||
case Qt::FontRole:
|
||||
{
|
||||
if (col == Column::ColumnFileName && hasUnsavedChanges)
|
||||
{
|
||||
QFont boldFont;
|
||||
boldFont.setBold(true);
|
||||
return boldFont;
|
||||
}
|
||||
break;
|
||||
}
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
return QVariant();
|
||||
}
|
||||
|
||||
RulesFileInfoPtr RulesFileTableModel::GetRulesFileInfoPtr(const QModelIndex& index) const
|
||||
{
|
||||
AZStd::string key = GetFileKey(index);
|
||||
if (key.empty())
|
||||
{
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
return m_rulesFileInfoMap.at(key);
|
||||
}
|
||||
|
||||
} // namespace AssetBundler
|
||||
@@ -0,0 +1,88 @@
|
||||
/*
|
||||
* 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.
|
||||
*
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <source/models/AssetBundlerAbstractFileTableModel.h>
|
||||
#include <source/utils/utils.h>
|
||||
|
||||
#include <AzToolsFramework/Asset/AssetBundler.h>
|
||||
|
||||
#include <QDateTime>
|
||||
|
||||
namespace AssetBundler
|
||||
{
|
||||
|
||||
//! Stores information about a Rules file on disk.
|
||||
struct RulesFileInfo
|
||||
{
|
||||
RulesFileInfo(const AZStd::string& absolutePath, const QString& fileName, bool loadFromFile);
|
||||
|
||||
bool SaveRulesFile();
|
||||
|
||||
AZStd::string m_absolutePath;
|
||||
QString m_fileName;
|
||||
QDateTime m_fileModificationTime;
|
||||
bool m_hasUnsavedChanges = false;
|
||||
|
||||
AZStd::shared_ptr<AzToolsFramework::AssetFileInfoListComparison> m_comparisonSteps;
|
||||
};
|
||||
|
||||
using RulesFileInfoPtr = AZStd::shared_ptr<RulesFileInfo>;
|
||||
using RulesFileInfoMap = AZStd::unordered_map<AZStd::string, RulesFileInfoPtr>;
|
||||
|
||||
|
||||
class RulesFileTableModel
|
||||
: public AssetBundlerAbstractFileTableModel
|
||||
{
|
||||
public:
|
||||
RulesFileTableModel();
|
||||
virtual ~RulesFileTableModel() {}
|
||||
|
||||
AZStd::vector<AZStd::string> CreateNewFiles(const AZStd::string& absoluteFilePath, const AzFramework::PlatformFlags& platforms = AzFramework::PlatformFlags::Platform_NONE, const QString& project = QString()) override;
|
||||
|
||||
bool DeleteFile(const QModelIndex& index) override;
|
||||
|
||||
void LoadFile(const AZStd::string& absoluteFilePath, const AZStd::string& projectName = "", bool isDefaultFile = false) override;
|
||||
|
||||
bool WriteToDisk(const AZStd::string& key) override;
|
||||
|
||||
AZStd::string GetFileAbsolutePath(const QModelIndex& index) const override;
|
||||
|
||||
int GetFileNameColumnIndex() const override;
|
||||
|
||||
int GetTimeStampColumnIndex() const override;
|
||||
|
||||
AZStd::shared_ptr<AzToolsFramework::AssetFileInfoListComparison> GetComparisonSteps(const QModelIndex& index) const;
|
||||
|
||||
bool MarkFileChanged(const QModelIndex& index);
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////
|
||||
// QAbstractTableModel overrides
|
||||
int columnCount(const QModelIndex& parent = QModelIndex()) const override;
|
||||
QVariant headerData(int section, Qt::Orientation orientation, int role) const override;
|
||||
QVariant data(const QModelIndex& index, int role) const override;
|
||||
//////////////////////////////////////////////////////////////////////////
|
||||
|
||||
enum Column
|
||||
{
|
||||
ColumnFileName,
|
||||
ColumnFileModificationTime,
|
||||
Max
|
||||
};
|
||||
|
||||
private:
|
||||
RulesFileInfoMap m_rulesFileInfoMap;
|
||||
|
||||
RulesFileInfoPtr GetRulesFileInfoPtr(const QModelIndex& index) const;
|
||||
};
|
||||
} // namespace AssetBundler
|
||||
@@ -0,0 +1,601 @@
|
||||
/*
|
||||
* 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 <source/models/SeedListFileTableModel.h>
|
||||
#include <source/models/SeedListTableModel.h>
|
||||
|
||||
#include <source/ui/SeedTabWidget.h>
|
||||
#include <source/utils/utils.h>
|
||||
|
||||
#include <AzCore/Outcome/Outcome.h>
|
||||
#include <AzCore/std/smart_ptr/make_shared.h>
|
||||
#include <AzFramework/IO/LocalFileIO.h>
|
||||
#include <AzFramework/StringFunc/StringFunc.h>
|
||||
#include <AzToolsFramework/AssetCatalog/PlatformAddressedAssetCatalog.h>
|
||||
|
||||
#include <QFileInfo>
|
||||
#include <QFont>
|
||||
|
||||
namespace AssetBundler
|
||||
{
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
// SeedListFileInfo
|
||||
//////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
SeedListFileInfo::SeedListFileInfo(
|
||||
const AZStd::string& absolutePath,
|
||||
const QString& fileName,
|
||||
const QString& project,
|
||||
bool loadFromFile,
|
||||
bool isDefaultSeedList,
|
||||
const AZStd::vector<AZStd::string>& defaultSeeds,
|
||||
const AzFramework::PlatformFlags& platforms)
|
||||
: m_absolutePath(absolutePath)
|
||||
, m_fileName(fileName)
|
||||
, m_project(project)
|
||||
, m_isDefaultSeedList(isDefaultSeedList)
|
||||
{
|
||||
AzFramework::StringFunc::Path::Normalize(m_absolutePath);
|
||||
|
||||
// Load the contents of the seed file into memory
|
||||
if (loadFromFile)
|
||||
{
|
||||
m_seedListModel.reset(new SeedListTableModel(nullptr, absolutePath));
|
||||
QFileInfo fileInfo(m_absolutePath.c_str());
|
||||
m_fileModificationTime = fileInfo.fileTime(QFileDevice::FileModificationTime);
|
||||
}
|
||||
else
|
||||
{
|
||||
m_seedListModel.reset(new SeedListTableModel(nullptr, "", defaultSeeds, platforms));
|
||||
m_fileModificationTime = QDateTime::currentDateTime();
|
||||
}
|
||||
}
|
||||
|
||||
bool SeedListFileInfo::SaveSeedFile()
|
||||
{
|
||||
if (m_seedListModel->Save(m_absolutePath))
|
||||
{
|
||||
m_fileModificationTime = QDateTime::currentDateTime();
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
bool SeedListFileInfo::HasUnsavedChanges()
|
||||
{
|
||||
return m_seedListModel->HasUnsavedChanges();
|
||||
}
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
// SeedListFileTableModel
|
||||
//////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
SeedListFileTableModel::SeedListFileTableModel(SeedTabWidget* parentSeedTabWidget)
|
||||
: AssetBundlerAbstractFileTableModel()
|
||||
, m_seedTabWidget(parentSeedTabWidget)
|
||||
{
|
||||
m_inMemoryDefaultSeedList.reset(new SeedListFileInfo("", "", "", false));
|
||||
}
|
||||
|
||||
SeedListFileTableModel::~SeedListFileTableModel()
|
||||
{
|
||||
m_seedTabWidget = nullptr;
|
||||
}
|
||||
|
||||
void SeedListFileTableModel::AddDefaultSeedsToInMemoryList(const AZStd::vector<AZStd::string>& defaultSeeds, const char* projectName, const AzFramework::PlatformFlags& platforms)
|
||||
{
|
||||
m_inMemoryDefaultSeedList.reset(new SeedListFileInfo(m_inMemoryDefaultSeedListKey, tr("DefaultSeeds"), QString(projectName), false, true, defaultSeeds, platforms));
|
||||
}
|
||||
|
||||
AZStd::vector<AZStd::string> SeedListFileTableModel::CreateNewFiles(const AZStd::string& absoluteFilePath, const AzFramework::PlatformFlags& /*platforms*/, const QString& project)
|
||||
{
|
||||
if (absoluteFilePath.empty())
|
||||
{
|
||||
AZ_Error(AssetBundler::AppWindowName, false, "Input file path is empty.");
|
||||
return {};
|
||||
}
|
||||
|
||||
// Get the file name without the extension for display purposes
|
||||
AZStd::string fileName;
|
||||
AzFramework::StringFunc::Path::GetFileName(absoluteFilePath.c_str(), fileName);
|
||||
|
||||
// Create a Seed List File and save it to disk
|
||||
AZStd::string key = AssetBundler::GenerateKeyFromAbsolutePath(absoluteFilePath);
|
||||
|
||||
AZStd::shared_ptr<SeedListFileInfo> newSeedListFile = AZStd::make_shared<SeedListFileInfo>(absoluteFilePath, QString(fileName.c_str()), project, false);
|
||||
newSeedListFile->m_seedListModel->SetHasUnsavedChanges(true);
|
||||
bool saveResult = newSeedListFile->SaveSeedFile();
|
||||
if (!saveResult)
|
||||
{
|
||||
AZ_Error(AssetBundler::AppWindowName, false, "Unable to create Seed List File: %s", absoluteFilePath.c_str());
|
||||
return {};
|
||||
}
|
||||
|
||||
// Add new file to the model
|
||||
m_seedListFileInfoMap[key] = newSeedListFile;
|
||||
AddFileKey(key);
|
||||
|
||||
AZStd::vector<AZStd::string> createdFiles = { absoluteFilePath };
|
||||
return createdFiles;
|
||||
}
|
||||
|
||||
bool SeedListFileTableModel::DeleteFile(const QModelIndex& index)
|
||||
{
|
||||
AZStd::string key = GetFileKey(index);
|
||||
if (key.empty())
|
||||
{
|
||||
// Error has already been thrown
|
||||
return false;
|
||||
}
|
||||
|
||||
if (m_seedListFileInfoMap.find(key) == m_seedListFileInfoMap.end())
|
||||
{
|
||||
AZ_Error(AssetBundler::AppWindowName, false, "Unable to find Seed File Info with key ( %s )", key.c_str());
|
||||
return false;
|
||||
}
|
||||
|
||||
SeedListFileInfoPtr seedFileInfo = m_seedListFileInfoMap[key];
|
||||
|
||||
// Remove file from disk
|
||||
const char* absolutePath = seedFileInfo->m_absolutePath.c_str();
|
||||
if (AZ::IO::FileIOBase::GetInstance()->Exists(absolutePath))
|
||||
{
|
||||
if (AZ::IO::FileIOBase::GetInstance()->IsReadOnly(absolutePath))
|
||||
{
|
||||
AZ_Error(AssetBundler::AppWindowName, false, "File (%s) is Read-Only. Please check your version control and try again.", absolutePath);
|
||||
return false;
|
||||
}
|
||||
|
||||
auto deleteResult = AZ::IO::FileIOBase::GetInstance()->Remove(absolutePath);
|
||||
if (!deleteResult)
|
||||
{
|
||||
AZ_Error(AssetBundler::AppWindowName, false, "Unable to delete: %s", absolutePath);
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
// Remove file from model
|
||||
m_seedListFileInfoMap.erase(key);
|
||||
RemoveFileKey(index);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
void SeedListFileTableModel::Reload(const char* fileExtension, const QSet<QString>& watchedFolders, const QSet<QString>& watchedFiles, const AZStd::unordered_map<AZStd::string, AZStd::string>& pathToProjectNameMap)
|
||||
{
|
||||
// Load in the Seed List files from disk
|
||||
AssetBundlerAbstractFileTableModel::Reload(fileExtension, watchedFolders, watchedFiles, pathToProjectNameMap);
|
||||
|
||||
// Add the in-memory Default Seed List to the model
|
||||
m_seedListFileInfoMap[m_inMemoryDefaultSeedListKey] = m_inMemoryDefaultSeedList;
|
||||
AddFileKey(m_inMemoryDefaultSeedListKey);
|
||||
}
|
||||
|
||||
void SeedListFileTableModel::LoadFile(const AZStd::string& absoluteFilePath, const AZStd::string& projectName, bool isDefaultFile)
|
||||
{
|
||||
// Get the file name without the extension for display purposes
|
||||
AZStd::string fileName;
|
||||
AzFramework::StringFunc::Path::GetFileName(absoluteFilePath.c_str(), fileName);
|
||||
|
||||
// Read the SeedListFile into memory and store it
|
||||
AZStd::string key = AssetBundler::GenerateKeyFromAbsolutePath(absoluteFilePath);
|
||||
auto fileInfoIt = m_seedListFileInfoMap.find(key);
|
||||
if (fileInfoIt != m_seedListFileInfoMap.end() && fileInfoIt->second->HasUnsavedChanges())
|
||||
{
|
||||
AZ_Warning(AssetBundler::AppWindowName, false, "Seed List File %s has unsaved changes and couldn't be reloaded", absoluteFilePath.c_str());
|
||||
return;
|
||||
}
|
||||
|
||||
AZStd::string projectNameOnDisplay = projectName;
|
||||
if (projectName.empty())
|
||||
{
|
||||
auto outcome = AssetBundler::GetCurrentProjectName();
|
||||
if (!outcome.IsSuccess())
|
||||
{
|
||||
AZ_Error(AssetBundler::AppWindowName, false, outcome.TakeError().c_str());
|
||||
return;
|
||||
}
|
||||
|
||||
projectNameOnDisplay = outcome.TakeValue();
|
||||
}
|
||||
|
||||
m_seedListFileInfoMap[key].reset(new SeedListFileInfo(absoluteFilePath, QString(fileName.c_str()), QString(projectNameOnDisplay.c_str()), true, isDefaultFile));
|
||||
AddFileKey(key);
|
||||
}
|
||||
|
||||
void SeedListFileTableModel::SelectDefaultSeedLists(bool setSelected)
|
||||
{
|
||||
for (const AZStd::string& key : GetAllFileKeys())
|
||||
{
|
||||
auto seedFileInfo = m_seedListFileInfoMap[key];
|
||||
if (!seedFileInfo->m_isDefaultSeedList)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
seedFileInfo->m_isChecked = setSelected;
|
||||
if(setSelected)
|
||||
{
|
||||
m_checkedSeedListFiles.insert(key);
|
||||
}
|
||||
else
|
||||
{
|
||||
m_checkedSeedListFiles.erase(key);
|
||||
}
|
||||
}
|
||||
|
||||
m_seedTabWidget->SetGenerateAssetListsButtonEnabled(!m_checkedSeedListFiles.empty());
|
||||
|
||||
// Update the Check State display of all elements
|
||||
QModelIndex firstIndex = index(0, 0);
|
||||
QModelIndex lastIndex = index(rowCount() - 1, columnCount() - 1);
|
||||
emit dataChanged(firstIndex, lastIndex, { Qt::CheckStateRole });
|
||||
}
|
||||
|
||||
AZStd::vector<AZStd::string> SeedListFileTableModel::GenerateAssetLists(const AZStd::string& absoluteFilePath, const AzFramework::PlatformFlags& platforms)
|
||||
{
|
||||
if (!m_checkedSeedListFiles.size())
|
||||
{
|
||||
AZ_Error(AssetBundler::AppWindowName, false, "Cannot Generate Asset List File(s): No Seed List Files are selected");
|
||||
return {};
|
||||
}
|
||||
|
||||
if (absoluteFilePath.empty())
|
||||
{
|
||||
AZ_Error(AssetBundler::AppWindowName, false, "File path cannot be empty");
|
||||
return {};
|
||||
}
|
||||
|
||||
if(platforms == AzFramework::PlatformFlags::Platform_NONE)
|
||||
{
|
||||
AZ_Error(AssetBundler::AppWindowName, false, "Input platform cannot be empty");
|
||||
return {};
|
||||
}
|
||||
|
||||
// Get all of the Seeds into one AssetSeedManager
|
||||
AzToolsFramework::AssetSeedManager assetSeedManager;
|
||||
|
||||
if (m_checkedSeedListFiles.find(m_inMemoryDefaultSeedListKey) != m_checkedSeedListFiles.end())
|
||||
{
|
||||
// The In-Memory Default Seed List can't be loaded from a file on disk, it is a special case
|
||||
assetSeedManager = *m_inMemoryDefaultSeedList->m_seedListModel->GetSeedListManager().get();
|
||||
m_checkedSeedListFiles.erase(m_inMemoryDefaultSeedListKey);
|
||||
}
|
||||
|
||||
for (const auto& checkedSeedFileKey : m_checkedSeedListFiles)
|
||||
{
|
||||
assetSeedManager.Load(m_seedListFileInfoMap[checkedSeedFileKey]->m_absolutePath);
|
||||
}
|
||||
|
||||
// Generate an AssetList for every input platform
|
||||
AZStd::vector<AZStd::string> createdFiles;
|
||||
for (const auto& platformIndex : AzFramework::PlatformHelper::GetPlatformIndicesInterpreted(platforms))
|
||||
{
|
||||
AZStd::string platformSpecificCachePath = AzToolsFramework::PlatformAddressedAssetCatalog::GetCatalogRegistryPathForPlatform(platformIndex);
|
||||
AzFramework::StringFunc::Path::StripFullName(platformSpecificCachePath);
|
||||
|
||||
FilePath platformSpecificPath(absoluteFilePath, AZStd::string(AzFramework::PlatformHelper::GetPlatformName(platformIndex)));
|
||||
if (assetSeedManager.SaveAssetFileInfo(platformSpecificPath.AbsolutePath(), AzFramework::PlatformHelper::GetPlatformFlagFromPlatformIndex(platformIndex)))
|
||||
{
|
||||
createdFiles.emplace_back(platformSpecificPath.AbsolutePath());
|
||||
}
|
||||
}
|
||||
|
||||
return createdFiles;
|
||||
}
|
||||
|
||||
QSharedPointer<SeedListTableModel> SeedListFileTableModel::GetSeedListFileContents(const QModelIndex& index)
|
||||
{
|
||||
auto seedFileInfoOutcome = GetSeedFileInfo(index);
|
||||
if (!seedFileInfoOutcome.IsSuccess())
|
||||
{
|
||||
return QSharedPointer<SeedListTableModel>();
|
||||
}
|
||||
|
||||
return seedFileInfoOutcome.GetValue()->m_seedListModel;
|
||||
}
|
||||
|
||||
bool SeedListFileTableModel::SetSeedPlatforms(const QModelIndex& seedFileIndex, const QModelIndex& seedIndex, const AzFramework::PlatformFlags& platforms)
|
||||
{
|
||||
AZStd::string key = GetFileKey(seedFileIndex);
|
||||
if (key.empty())
|
||||
{
|
||||
// Error has already been thrown
|
||||
return false;
|
||||
}
|
||||
|
||||
if (m_seedListFileInfoMap.find(key) == m_seedListFileInfoMap.end())
|
||||
{
|
||||
AZ_Error(AssetBundler::AppWindowName, false, "Unable to find Seed File Info with key ( %s )", key.c_str());
|
||||
return false;
|
||||
}
|
||||
|
||||
SeedListFileInfoPtr seedFileInfo = m_seedListFileInfoMap[key];
|
||||
if (!seedFileInfo->m_seedListModel->SetSeedPlatforms(seedIndex, platforms))
|
||||
{
|
||||
// Error has already been thrown
|
||||
return false;
|
||||
}
|
||||
|
||||
// Update display so the user knows there are unsaved changes
|
||||
m_keysWithUnsavedChanges.insert(key);
|
||||
QModelIndex changedIndex = QAbstractTableModel::index(seedFileIndex.row(), Column::ColumnFileName);
|
||||
emit dataChanged(changedIndex, changedIndex, { Qt::DisplayRole, Qt::FontRole });
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool SeedListFileTableModel::AddSeed(const QModelIndex& seedFileIndex, const AZStd::string& seedRelativePath, const AzFramework::PlatformFlags& platforms)
|
||||
{
|
||||
AZStd::string key = GetFileKey(seedFileIndex);
|
||||
if (key.empty())
|
||||
{
|
||||
// Error has already been thrown
|
||||
return false;
|
||||
}
|
||||
|
||||
if (m_seedListFileInfoMap.find(key) == m_seedListFileInfoMap.end())
|
||||
{
|
||||
AZ_Error(AssetBundler::AppWindowName, false, "Unable to find Seed File Info with key ( %s )", key.c_str());
|
||||
return false;
|
||||
}
|
||||
|
||||
SeedListFileInfoPtr seedFileInfo = m_seedListFileInfoMap[key];
|
||||
if (!seedFileInfo->m_seedListModel->AddSeed(seedRelativePath, platforms))
|
||||
{
|
||||
// Error has already been thrown
|
||||
return false;
|
||||
}
|
||||
|
||||
// Update display so the user knows there are unsaved changes
|
||||
m_keysWithUnsavedChanges.insert(key);
|
||||
QModelIndex changedIndex = QAbstractTableModel::index(seedFileIndex.row(), Column::ColumnFileName);
|
||||
emit dataChanged(changedIndex, changedIndex, { Qt::DisplayRole, Qt::FontRole });
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool SeedListFileTableModel::RemoveSeed(const QModelIndex& seedFileIndex, const QModelIndex& seedIndex)
|
||||
{
|
||||
AZStd::string key = GetFileKey(seedFileIndex);
|
||||
if (key.empty())
|
||||
{
|
||||
// Error has already been thrown
|
||||
return false;
|
||||
}
|
||||
|
||||
if (m_seedListFileInfoMap.find(key) == m_seedListFileInfoMap.end())
|
||||
{
|
||||
AZ_Error(AssetBundler::AppWindowName, false, "Unable to find Seed File Info with key ( %s )", key.c_str());
|
||||
return false;
|
||||
}
|
||||
|
||||
SeedListFileInfoPtr seedFileInfo = m_seedListFileInfoMap[key];
|
||||
if (!seedFileInfo->m_seedListModel->RemoveSeed(seedIndex))
|
||||
{
|
||||
// Error has already been thrown
|
||||
return false;
|
||||
}
|
||||
|
||||
// Update display so the user knows there are unsaved changes
|
||||
m_keysWithUnsavedChanges.insert(key);
|
||||
QModelIndex changedIndex = QAbstractTableModel::index(seedFileIndex.row(), Column::ColumnFileName);
|
||||
emit dataChanged(changedIndex, changedIndex, { Qt::DisplayRole, Qt::FontRole });
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool SeedListFileTableModel::WriteToDisk(const AZStd::string& key)
|
||||
{
|
||||
if (key == m_inMemoryDefaultSeedListKey)
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
auto seedListFileIt = m_seedListFileInfoMap.find(key);
|
||||
return seedListFileIt != m_seedListFileInfoMap.end() && seedListFileIt->second->SaveSeedFile();
|
||||
}
|
||||
|
||||
AZStd::string SeedListFileTableModel::GetFileAbsolutePath(const QModelIndex& index) const
|
||||
{
|
||||
auto seedFileInfoOutcome = GetSeedFileInfo(index);
|
||||
if (!seedFileInfoOutcome.IsSuccess() || seedFileInfoOutcome.GetValue()->m_absolutePath == m_inMemoryDefaultSeedListKey)
|
||||
{
|
||||
// Error has already been thrown
|
||||
return AZStd::string();
|
||||
}
|
||||
return seedFileInfoOutcome.GetValue()->m_absolutePath;
|
||||
}
|
||||
|
||||
int SeedListFileTableModel::GetFileNameColumnIndex() const
|
||||
{
|
||||
return Column::ColumnFileName;
|
||||
}
|
||||
|
||||
int SeedListFileTableModel::GetTimeStampColumnIndex() const
|
||||
{
|
||||
return Column::ColumnFileModificationTime;
|
||||
}
|
||||
|
||||
int SeedListFileTableModel::columnCount(const QModelIndex& parent) const
|
||||
{
|
||||
return parent.isValid() ? 0 : Column::Max;
|
||||
}
|
||||
|
||||
QVariant SeedListFileTableModel::headerData(int section, Qt::Orientation orientation, int role) const
|
||||
{
|
||||
if (role == Qt::DisplayRole && orientation == Qt::Horizontal)
|
||||
{
|
||||
switch (section)
|
||||
{
|
||||
case Column::ColumnFileName:
|
||||
return QString(tr("Seed List File"));
|
||||
case Column::ColumnProject:
|
||||
return QString(tr("Project Source"));
|
||||
case Column::ColumnFileModificationTime:
|
||||
return QString(tr("Modification Time"));
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
return QVariant();
|
||||
}
|
||||
|
||||
QVariant SeedListFileTableModel::data(const QModelIndex& index, int role) const
|
||||
{
|
||||
auto seedFileInfoOutcome = GetSeedFileInfo(index);
|
||||
if (!seedFileInfoOutcome.IsSuccess())
|
||||
{
|
||||
return QVariant();
|
||||
}
|
||||
|
||||
int col = index.column();
|
||||
bool hasUnsavedChanges = seedFileInfoOutcome.GetValue()->m_seedListModel->HasUnsavedChanges();
|
||||
|
||||
switch (role)
|
||||
{
|
||||
case Qt::DisplayRole:
|
||||
[[fallthrough]];
|
||||
case SortRole:
|
||||
{
|
||||
if (col == Column::ColumnFileName)
|
||||
{
|
||||
QString displayName = seedFileInfoOutcome.GetValue()->m_fileName;
|
||||
if (hasUnsavedChanges)
|
||||
{
|
||||
displayName.append("*");
|
||||
}
|
||||
return displayName;
|
||||
}
|
||||
else if (col == Column::ColumnProject)
|
||||
{
|
||||
return seedFileInfoOutcome.GetValue()->m_project;
|
||||
}
|
||||
else if (col == Column::ColumnFileModificationTime)
|
||||
{
|
||||
if (role == SortRole)
|
||||
{
|
||||
return seedFileInfoOutcome.GetValue()->m_fileModificationTime;
|
||||
}
|
||||
else
|
||||
{
|
||||
return seedFileInfoOutcome.GetValue()->m_fileModificationTime.toString(DateTimeFormat);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
// Returning an empty QString will ensure the checkboxes do not have any text displayed next to them
|
||||
return QString();
|
||||
}
|
||||
}
|
||||
case Qt::FontRole:
|
||||
{
|
||||
if (col == Column::ColumnFileName && hasUnsavedChanges)
|
||||
{
|
||||
QFont boldFont;
|
||||
boldFont.setBold(true);
|
||||
return boldFont;
|
||||
}
|
||||
}
|
||||
case Qt::CheckStateRole:
|
||||
{
|
||||
if (col == Column::ColumnCheckBox)
|
||||
{
|
||||
if (seedFileInfoOutcome.GetValue()->m_isChecked)
|
||||
{
|
||||
return Qt::Checked;
|
||||
}
|
||||
else
|
||||
{
|
||||
return Qt::Unchecked;
|
||||
}
|
||||
}
|
||||
}
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
return QVariant();
|
||||
}
|
||||
|
||||
bool SeedListFileTableModel::setData(const QModelIndex& index, const QVariant& value, int role)
|
||||
{
|
||||
if (role != Qt::CheckStateRole || index.column() != Column::ColumnCheckBox)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
AZStd::string key = GetFileKey(index);
|
||||
if (key.empty())
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
auto seedFileInfo = m_seedListFileInfoMap.find(key);
|
||||
if (seedFileInfo == m_seedListFileInfoMap.end())
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
if (value == Qt::CheckState::Unchecked)
|
||||
{
|
||||
seedFileInfo->second->m_isChecked = false;
|
||||
m_checkedSeedListFiles.erase(key);
|
||||
|
||||
if (seedFileInfo->second->m_isDefaultSeedList)
|
||||
{
|
||||
m_seedTabWidget->UncheckSelectDefaultSeedListsCheckBox();
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
seedFileInfo->second->m_isChecked = true;
|
||||
m_checkedSeedListFiles.insert(key);
|
||||
}
|
||||
|
||||
m_seedTabWidget->SetGenerateAssetListsButtonEnabled(!m_checkedSeedListFiles.empty());
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
Qt::ItemFlags SeedListFileTableModel::flags(const QModelIndex& index) const
|
||||
{
|
||||
if (index.column() == Column::ColumnCheckBox)
|
||||
{
|
||||
return Qt::ItemIsUserCheckable | QAbstractTableModel::flags(index);
|
||||
}
|
||||
|
||||
return QAbstractTableModel::flags(index);
|
||||
}
|
||||
|
||||
AZ::Outcome<SeedListFileInfoPtr, void> SeedListFileTableModel::GetSeedFileInfo(const QModelIndex& index) const
|
||||
{
|
||||
AZStd::string key = GetFileKey(index);
|
||||
if (key.empty())
|
||||
{
|
||||
// Error has already been thrown
|
||||
return AZ::Failure();
|
||||
}
|
||||
|
||||
if (m_seedListFileInfoMap.find(key) != m_seedListFileInfoMap.end())
|
||||
{
|
||||
return AZ::Success(m_seedListFileInfoMap.at(key));
|
||||
}
|
||||
else
|
||||
{
|
||||
AZ_Error(AssetBundler::AppWindowName, false, "Cannot find Seed File Info");
|
||||
return AZ::Failure();
|
||||
}
|
||||
}
|
||||
|
||||
} // namespace AssetBundler
|
||||
@@ -0,0 +1,134 @@
|
||||
/*
|
||||
* 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.
|
||||
*
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <source/models/AssetBundlerAbstractFileTableModel.h>
|
||||
|
||||
#include <AzToolsFramework/Asset/AssetSeedManager.h>
|
||||
#include <AzFramework/Platform/PlatformDefaults.h>
|
||||
|
||||
#include <QDateTime>
|
||||
#include <QSharedPointer>
|
||||
|
||||
namespace AssetBundler
|
||||
{
|
||||
class SeedListTableModel;
|
||||
|
||||
class SeedTabWidget;
|
||||
|
||||
struct SeedListFileInfo
|
||||
{
|
||||
/**
|
||||
* Stores information about a Seed List File on disk.
|
||||
*
|
||||
* @param absolutePath The absolute path of the Seed List File
|
||||
* @param fileName The name of the Seed List File. This does not include the ".seed" file extension
|
||||
* @param project The area of the codebase the Seed List File is from (ex: ProjectName, Engine, Gem)
|
||||
* @param loadFromFile Set to True if you wish to load an existing Seed List File into memory. Set to False if you are creating a new Seed List File.
|
||||
*/
|
||||
SeedListFileInfo(
|
||||
const AZStd::string& absolutePath,
|
||||
const QString& fileName,
|
||||
const QString& project,
|
||||
bool loadFromFile,
|
||||
bool isDefaultSeedList = false,
|
||||
const AZStd::vector<AZStd::string>& defaultSeeds = AZStd::vector<AZStd::string>(),
|
||||
const AzFramework::PlatformFlags& platforms = AzFramework::PlatformFlags::Platform_NONE);
|
||||
|
||||
bool SaveSeedFile();
|
||||
|
||||
bool HasUnsavedChanges();
|
||||
|
||||
AZStd::string m_absolutePath;
|
||||
bool m_isChecked = false;
|
||||
bool m_isDefaultSeedList = false;
|
||||
QString m_fileName;
|
||||
QString m_project;
|
||||
QDateTime m_fileModificationTime;
|
||||
|
||||
QSharedPointer<SeedListTableModel> m_seedListModel;
|
||||
};
|
||||
|
||||
using SeedListFileInfoPtr = AZStd::shared_ptr<SeedListFileInfo>;
|
||||
/// Stores SeedListFileInfo, using the absolute path (without the drive letter) of the Seed List file as the key
|
||||
using SeedListFileInfoMap = AZStd::unordered_map<AZStd::string, SeedListFileInfoPtr>;
|
||||
|
||||
class SeedListFileTableModel
|
||||
: public AssetBundlerAbstractFileTableModel
|
||||
{
|
||||
|
||||
public:
|
||||
explicit SeedListFileTableModel(SeedTabWidget* parentSeedTabWidget);
|
||||
virtual ~SeedListFileTableModel();
|
||||
|
||||
void AddDefaultSeedsToInMemoryList(const AZStd::vector<AZStd::string>& defaultSeeds, const char* projectName, const AzFramework::PlatformFlags& platforms);
|
||||
|
||||
AZStd::vector<AZStd::string> CreateNewFiles(const AZStd::string& absoluteFilePath, const AzFramework::PlatformFlags& platforms, const QString& project) override;
|
||||
|
||||
bool DeleteFile(const QModelIndex& index) override;
|
||||
|
||||
void Reload(const char* fileExtension, const QSet<QString>& watchedFolders, const QSet<QString>& watchedFiles = QSet<QString>(), const AZStd::unordered_map<AZStd::string, AZStd::string>& pathToProjectNameMap = AZStd::unordered_map<AZStd::string, AZStd::string>()) override;
|
||||
|
||||
void LoadFile(const AZStd::string& absoluteFilePath, const AZStd::string& projectName = "", bool isDefaultFile = false) override;
|
||||
|
||||
void SelectDefaultSeedLists(bool setSelected);
|
||||
|
||||
AZStd::vector<AZStd::string> GenerateAssetLists(const AZStd::string& absoluteFilePath, const AzFramework::PlatformFlags& platforms);
|
||||
|
||||
QSharedPointer<SeedListTableModel> GetSeedListFileContents(const QModelIndex& index);
|
||||
|
||||
bool SetSeedPlatforms(const QModelIndex& seedFileIndex, const QModelIndex& seedIndex, const AzFramework::PlatformFlags& platforms);
|
||||
|
||||
bool AddSeed(const QModelIndex& seedFileIndex, const AZStd::string& seedRelativePath, const AzFramework::PlatformFlags& platforms);
|
||||
|
||||
bool RemoveSeed(const QModelIndex& seedFileIndex, const QModelIndex& seedIndex);
|
||||
|
||||
bool WriteToDisk(const AZStd::string& key) override;
|
||||
|
||||
AZStd::string GetFileAbsolutePath(const QModelIndex& index) const override;
|
||||
|
||||
int GetFileNameColumnIndex() const override;
|
||||
|
||||
int GetTimeStampColumnIndex() const override;
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////
|
||||
// QAbstractListModel overrides
|
||||
int columnCount(const QModelIndex& parent = QModelIndex()) const override;
|
||||
QVariant headerData(int section, Qt::Orientation orientation, int role) const override;
|
||||
QVariant data(const QModelIndex& index, int role) const override;
|
||||
bool setData(const QModelIndex& index, const QVariant& value, int role = Qt::CheckStateRole) override;
|
||||
Qt::ItemFlags flags(const QModelIndex& index) const override;
|
||||
//////////////////////////////////////////////////////////////////////////
|
||||
|
||||
enum Column
|
||||
{
|
||||
ColumnCheckBox,
|
||||
ColumnFileName,
|
||||
ColumnProject,
|
||||
ColumnFileModificationTime,
|
||||
Max
|
||||
};
|
||||
|
||||
private:
|
||||
AZ::Outcome<SeedListFileInfoPtr, void> GetSeedFileInfo(const QModelIndex& index) const;
|
||||
|
||||
SeedListFileInfoMap m_seedListFileInfoMap;
|
||||
AZStd::unordered_set<AZStd::string> m_checkedSeedListFiles;
|
||||
|
||||
AZStd::string m_inMemoryDefaultSeedListKey = "InMemoryDefaultKey";
|
||||
SeedListFileInfoPtr m_inMemoryDefaultSeedList;
|
||||
|
||||
SeedTabWidget* m_seedTabWidget = nullptr;
|
||||
};
|
||||
|
||||
} // namespace AssetBundler
|
||||
@@ -0,0 +1,270 @@
|
||||
/*
|
||||
* 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 <source/models/SeedListTableModel.h>
|
||||
|
||||
#include <source/utils/utils.h>
|
||||
|
||||
#include <AzCore/Outcome/Outcome.h>
|
||||
#include <AzCore/std/smart_ptr/make_shared.h>
|
||||
#include <AzFramework/IO/LocalFileIO.h>
|
||||
#include <AzFramework/StringFunc/StringFunc.h>
|
||||
#include <AzToolsFramework/AssetCatalog/PlatformAddressedAssetCatalog.h>
|
||||
|
||||
#include <QFont>
|
||||
|
||||
namespace AssetBundler
|
||||
{
|
||||
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
// AdditionalSeedInfo
|
||||
//////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
AdditionalSeedInfo::AdditionalSeedInfo(const QString& relativePath, const QString& platformList)
|
||||
: m_relativePath(relativePath)
|
||||
, m_platformList(platformList)
|
||||
{
|
||||
}
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
// SeedListTableModel
|
||||
//////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
SeedListTableModel::SeedListTableModel(QObject* parent, const AZStd::string& absolutePath, const AZStd::vector<AZStd::string>& defaultSeeds, const AzFramework::PlatformFlags& platforms)
|
||||
: QAbstractTableModel(parent)
|
||||
{
|
||||
m_seedListManager.reset(new AzToolsFramework::AssetSeedManager());
|
||||
|
||||
if (absolutePath.empty() && defaultSeeds.empty())
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
if (!defaultSeeds.empty())
|
||||
{
|
||||
for (const AZStd::string& seed : defaultSeeds)
|
||||
{
|
||||
m_seedListManager->AddSeedAssetForValidPlatforms(seed, platforms);
|
||||
}
|
||||
|
||||
m_isFileOnDisk = false;
|
||||
}
|
||||
else
|
||||
{
|
||||
m_seedListManager->Load(absolutePath);
|
||||
}
|
||||
|
||||
AZ::Data::AssetInfo assetInfo;
|
||||
QString platformList;
|
||||
for (const auto& seed : m_seedListManager->GetAssetSeedList())
|
||||
{
|
||||
assetInfo = AzToolsFramework::AssetSeedManager::GetAssetInfoById(seed.m_assetId, AzFramework::PlatformHelper::GetPlatformIndicesInterpreted(seed.m_platformFlags)[0], absolutePath);
|
||||
platformList = QString(m_seedListManager->GetReadablePlatformList(seed).c_str());
|
||||
|
||||
m_additionalSeedInfoMap[seed.m_assetId].reset(new AdditionalSeedInfo(assetInfo.m_relativePath.c_str(), platformList));
|
||||
}
|
||||
}
|
||||
|
||||
AZ::Outcome<AzFramework::PlatformFlags, void> SeedListTableModel::GetSeedPlatforms(const QModelIndex& index) const
|
||||
{
|
||||
auto seedOutcome = GetSeedInfo(index);
|
||||
if (!seedOutcome.IsSuccess())
|
||||
{
|
||||
// Error has already been thrown
|
||||
return AZ::Failure();
|
||||
}
|
||||
|
||||
return AZ::Success(seedOutcome.GetValue().m_platformFlags);
|
||||
}
|
||||
|
||||
bool SeedListTableModel::Save(const AZStd::string& absolutePath)
|
||||
{
|
||||
if (!HasUnsavedChanges())
|
||||
{
|
||||
// There are no changes, so there is nothing to save
|
||||
return true;
|
||||
}
|
||||
|
||||
SetHasUnsavedChanges(!m_seedListManager->Save(absolutePath));
|
||||
return !HasUnsavedChanges();
|
||||
}
|
||||
|
||||
bool SeedListTableModel::SetSeedPlatforms(const QModelIndex& index, const AzFramework::PlatformFlags& platforms)
|
||||
{
|
||||
auto seedOutcome = GetSeedInfo(index);
|
||||
if (!seedOutcome.IsSuccess())
|
||||
{
|
||||
// Error has already been thrown
|
||||
return false;
|
||||
}
|
||||
|
||||
if (platforms == AzFramework::PlatformFlags::Platform_NONE)
|
||||
{
|
||||
AZ_Error(AssetBundler::AppWindowName, false, "Cannot Edit Platforms: No platforms were selected");
|
||||
return false;
|
||||
}
|
||||
|
||||
auto setPlatformOutcome = m_seedListManager->SetSeedPlatformFlags(index.row(), platforms);
|
||||
if (!setPlatformOutcome.IsSuccess())
|
||||
{
|
||||
AZ_Error(AssetBundler::AppWindowName, false, setPlatformOutcome.GetError().c_str());
|
||||
return false;
|
||||
}
|
||||
|
||||
// Update the cached display info
|
||||
auto additionalSeedInfo = m_additionalSeedInfoMap.find(seedOutcome.GetValue().m_assetId);
|
||||
if (additionalSeedInfo == m_additionalSeedInfoMap.end())
|
||||
{
|
||||
AZ_Error(AssetBundler::AppWindowName, false, "Unable to find additional Seed info");
|
||||
return false;
|
||||
}
|
||||
additionalSeedInfo->second->m_platformList = QString(AzFramework::PlatformHelper::GetCommaSeparatedPlatformList(platforms).c_str());
|
||||
|
||||
SetHasUnsavedChanges(true);
|
||||
|
||||
// Update the display
|
||||
QModelIndex firstChangedIndex = QAbstractTableModel::index(index.row(), Column::ColumnRelativePath);
|
||||
QModelIndex lastChangedIndex = QAbstractTableModel::index(index.row(), Column::Max - 1);
|
||||
emit dataChanged(firstChangedIndex, lastChangedIndex, { Qt::DisplayRole });
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool SeedListTableModel::AddSeed(const AZStd::string& seedRelativePath, const AzFramework::PlatformFlags& platforms)
|
||||
{
|
||||
AZStd::pair<AZ::Data::AssetId, AzFramework::PlatformFlags> addSeedsResult = m_seedListManager->AddSeedAssetForValidPlatforms(seedRelativePath, platforms);
|
||||
|
||||
if (!addSeedsResult.first.IsValid() || addSeedsResult.second == AzFramework::PlatformFlags::Platform_NONE)
|
||||
{
|
||||
// Error has already been thrown
|
||||
return false;
|
||||
}
|
||||
|
||||
QString platformList = QString(AzFramework::PlatformHelper::GetCommaSeparatedPlatformList(addSeedsResult.second).c_str());
|
||||
|
||||
int lastRowIndex = AZStd::max(rowCount() - 1, 0);
|
||||
beginInsertRows(QModelIndex(), lastRowIndex, lastRowIndex);
|
||||
|
||||
m_additionalSeedInfoMap[addSeedsResult.first].reset(new AdditionalSeedInfo(QString(seedRelativePath.c_str()), platformList));
|
||||
|
||||
endInsertRows();
|
||||
|
||||
SetHasUnsavedChanges(true);
|
||||
return true;
|
||||
}
|
||||
|
||||
bool SeedListTableModel::RemoveSeed(const QModelIndex& seedIndex)
|
||||
{
|
||||
auto seedOutcome = GetSeedInfo(seedIndex);
|
||||
if (!seedOutcome.IsSuccess())
|
||||
{
|
||||
// Error has already been thrown
|
||||
return false;
|
||||
}
|
||||
|
||||
int row = seedIndex.row();
|
||||
beginRemoveRows(QModelIndex(), row, row);
|
||||
m_seedListManager->RemoveSeedAsset(seedOutcome.GetValue().m_assetId, seedOutcome.GetValue().m_platformFlags);
|
||||
m_additionalSeedInfoMap.erase(seedOutcome.GetValue().m_assetId);
|
||||
endRemoveRows();
|
||||
|
||||
SetHasUnsavedChanges(true);
|
||||
return true;
|
||||
}
|
||||
|
||||
int SeedListTableModel::rowCount(const QModelIndex& parent) const
|
||||
{
|
||||
return parent.isValid() ? 0 : static_cast<int>(m_additionalSeedInfoMap.size());
|
||||
}
|
||||
|
||||
int SeedListTableModel::columnCount(const QModelIndex& parent) const
|
||||
{
|
||||
return parent.isValid() ? 0 : Column::Max;
|
||||
}
|
||||
|
||||
QVariant SeedListTableModel::headerData(int section, Qt::Orientation orientation, int role) const
|
||||
{
|
||||
if (role == Qt::DisplayRole && orientation == Qt::Horizontal)
|
||||
{
|
||||
switch (section)
|
||||
{
|
||||
case Column::ColumnRelativePath:
|
||||
return QString("Seed");
|
||||
case Column::ColumnPlatformList:
|
||||
return QString("Platforms");
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
return QVariant();
|
||||
}
|
||||
|
||||
QVariant SeedListTableModel::data(const QModelIndex& index, int role) const
|
||||
{
|
||||
auto additionalSeedInfoOutcome = GetAdditionalSeedInfo(index);
|
||||
if (!additionalSeedInfoOutcome.IsSuccess())
|
||||
{
|
||||
return QVariant();
|
||||
}
|
||||
|
||||
switch (role)
|
||||
{
|
||||
case Qt::DisplayRole:
|
||||
{
|
||||
if (index.column() == Column::ColumnRelativePath)
|
||||
{
|
||||
return additionalSeedInfoOutcome.GetValue()->m_relativePath;
|
||||
}
|
||||
else if (index.column() == Column::ColumnPlatformList)
|
||||
{
|
||||
return additionalSeedInfoOutcome.GetValue()->m_platformList;
|
||||
}
|
||||
}
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
return QVariant();
|
||||
}
|
||||
|
||||
AZ::Outcome<AzFramework::SeedInfo&, void> SeedListTableModel::GetSeedInfo(const QModelIndex& index) const
|
||||
{
|
||||
int row = index.row();
|
||||
int col = index.column();
|
||||
if (row >= rowCount() || row < 0 || col >= columnCount() || col < 0)
|
||||
{
|
||||
AZ_Error(AssetBundler::AppWindowName, false, "Selected index (%i, %i) is out of range", row, col);
|
||||
return AZ::Failure();
|
||||
}
|
||||
|
||||
return AZ::Success(m_seedListManager->GetAssetSeedList().at(row));
|
||||
}
|
||||
|
||||
AZ::Outcome<AdditionalSeedInfoPtr, void> SeedListTableModel::GetAdditionalSeedInfo(const QModelIndex& index) const
|
||||
{
|
||||
auto seedInfoOutcome = GetSeedInfo(index);
|
||||
if (!seedInfoOutcome.IsSuccess())
|
||||
{
|
||||
// Error has already been thrown
|
||||
return AZ::Failure();
|
||||
}
|
||||
|
||||
auto additionalSeedInfoIt = m_additionalSeedInfoMap.find(seedInfoOutcome.GetValue().m_assetId);
|
||||
if (additionalSeedInfoIt == m_additionalSeedInfoMap.end())
|
||||
{
|
||||
return AZ::Failure();
|
||||
}
|
||||
|
||||
return AZ::Success(additionalSeedInfoIt->second);
|
||||
}
|
||||
|
||||
} // namespace AssetBundler
|
||||
@@ -0,0 +1,84 @@
|
||||
/*
|
||||
* 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.
|
||||
*
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <source/models/AssetBundlerAbstractFileTableModel.h>
|
||||
|
||||
#include <AzToolsFramework/Asset/AssetSeedManager.h>
|
||||
#include <AzFramework/Platform/PlatformDefaults.h>
|
||||
|
||||
#include <QSharedPointer>
|
||||
|
||||
namespace AssetBundler
|
||||
{
|
||||
struct AdditionalSeedInfo
|
||||
{
|
||||
AdditionalSeedInfo(const QString& relativePath, const QString& platformList);
|
||||
|
||||
QString m_relativePath;
|
||||
QString m_platformList;
|
||||
};
|
||||
|
||||
using AdditionalSeedInfoPtr = AZStd::shared_ptr<AdditionalSeedInfo>;
|
||||
using AdditionalSeedInfoMap = AZStd::unordered_map<AZ::Data::AssetId, AdditionalSeedInfoPtr>;
|
||||
|
||||
class SeedListTableModel
|
||||
: public QAbstractTableModel
|
||||
{
|
||||
public:
|
||||
explicit SeedListTableModel(QObject* parent = nullptr, const AZStd::string& absolutePath = AZStd::string(), const AZStd::vector<AZStd::string>& defaultSeeds = AZStd::vector<AZStd::string>(), const AzFramework::PlatformFlags& platforms = AzFramework::PlatformFlags::Platform_NONE);
|
||||
virtual ~SeedListTableModel() {}
|
||||
|
||||
AZStd::shared_ptr<AzToolsFramework::AssetSeedManager> GetSeedListManager() { return m_seedListManager; }
|
||||
|
||||
bool HasUnsavedChanges() { return m_hasUnsavedChanges && m_isFileOnDisk; }
|
||||
|
||||
void SetHasUnsavedChanges(bool hasUnsavedChanges) { m_hasUnsavedChanges = hasUnsavedChanges; }
|
||||
|
||||
bool Save(const AZStd::string& absolutePath);
|
||||
|
||||
AZ::Outcome<AzFramework::PlatformFlags, void> GetSeedPlatforms(const QModelIndex& index) const;
|
||||
|
||||
bool SetSeedPlatforms(const QModelIndex& index, const AzFramework::PlatformFlags& platforms);
|
||||
|
||||
bool AddSeed(const AZStd::string& seedRelativePath, const AzFramework::PlatformFlags& platforms);
|
||||
|
||||
bool RemoveSeed(const QModelIndex& seedIndex);
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////
|
||||
// QAbstractListModel overrides
|
||||
int rowCount(const QModelIndex& parent = QModelIndex()) const override;
|
||||
int columnCount(const QModelIndex& parent = QModelIndex()) const override;
|
||||
QVariant headerData(int section, Qt::Orientation orientation, int role) const override;
|
||||
QVariant data(const QModelIndex& index, int role) const override;
|
||||
//////////////////////////////////////////////////////////////////////////
|
||||
|
||||
enum Column
|
||||
{
|
||||
ColumnRelativePath,
|
||||
ColumnPlatformList,
|
||||
Max
|
||||
};
|
||||
|
||||
private:
|
||||
AZ::Outcome<AzFramework::SeedInfo&, void> GetSeedInfo(const QModelIndex& index) const;
|
||||
|
||||
AZ::Outcome<AdditionalSeedInfoPtr, void> GetAdditionalSeedInfo(const QModelIndex& index) const;
|
||||
|
||||
AZStd::shared_ptr<AzToolsFramework::AssetSeedManager> m_seedListManager;
|
||||
AdditionalSeedInfoMap m_additionalSeedInfoMap;
|
||||
|
||||
bool m_hasUnsavedChanges = false;
|
||||
bool m_isFileOnDisk = true;
|
||||
};
|
||||
} // namespace AssetBundler
|
||||
@@ -0,0 +1,96 @@
|
||||
/*
|
||||
* 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 <source/ui/AddSeedDialog.h>
|
||||
#include <source/ui/ui_AddSeedDialog.h>
|
||||
|
||||
#include <source/ui/PlatformSelectionWidget.h>
|
||||
|
||||
#include <QFileDialog>
|
||||
#include <QPushButton>
|
||||
|
||||
const char QtRelativePathPrefix[] = "../";
|
||||
|
||||
namespace AssetBundler
|
||||
{
|
||||
AddSeedDialog::AddSeedDialog(QWidget* parent, const AzFramework::PlatformFlags& enabledPlatforms, const AZStd::string& platformSpecificCachePath)
|
||||
: QDialog(parent)
|
||||
, m_platformSpecificCachePath(platformSpecificCachePath.c_str())
|
||||
{
|
||||
m_ui.reset(new Ui::AddSeedDialog);
|
||||
m_ui->setupUi(this);
|
||||
|
||||
// Set up Browse File button
|
||||
m_ui->fileNameLineEdit->setReadOnly(true);
|
||||
connect(m_ui->browseFileButton, &QPushButton::clicked, this, &AddSeedDialog::OnBrowseFileButtonPressed);
|
||||
|
||||
// Set up Platform selection
|
||||
m_ui->platformSelectionWidget->Init(enabledPlatforms);
|
||||
connect(m_ui->platformSelectionWidget, &PlatformSelectionWidget::PlatformsSelected, this, &AddSeedDialog::OnPlatformSelectionChanged);
|
||||
|
||||
// Set up Cancel and Create New File buttons
|
||||
m_ui->addSeedButton->setEnabled(false);
|
||||
connect(m_ui->cancelButton, &QPushButton::clicked, this, &QDialog::reject);
|
||||
connect(m_ui->addSeedButton, &QPushButton::clicked, this, &QDialog::accept);
|
||||
}
|
||||
|
||||
AZStd::string AddSeedDialog::GetFileName()
|
||||
{
|
||||
return m_fileName;
|
||||
}
|
||||
|
||||
AzFramework::PlatformFlags AddSeedDialog::GetPlatformFlags()
|
||||
{
|
||||
return m_ui->platformSelectionWidget->GetSelectedPlatforms();
|
||||
}
|
||||
|
||||
void AddSeedDialog::OnBrowseFileButtonPressed()
|
||||
{
|
||||
QString seedAbsolutePath = QFileDialog::getOpenFileName(this, tr("Add New Seed"), m_platformSpecificCachePath);
|
||||
m_fileNameIsValid = !seedAbsolutePath.isEmpty();
|
||||
if (!m_fileNameIsValid)
|
||||
{
|
||||
// The user canceled out of the window, do not update anything
|
||||
return;
|
||||
}
|
||||
|
||||
// Make sure the path is relative to the platform-specific cache
|
||||
QDir platformSpecificCacheDir(m_platformSpecificCachePath);
|
||||
QString seedRelativePath = platformSpecificCacheDir.relativeFilePath(seedAbsolutePath);
|
||||
|
||||
// trim off the "../" from the relative path
|
||||
FormatRelativePathString(seedRelativePath);
|
||||
m_fileName = seedRelativePath.toUtf8().data();
|
||||
|
||||
// Update the ui
|
||||
m_ui->fileNameLineEdit->setText(seedRelativePath);
|
||||
m_ui->addSeedButton->setEnabled(m_platformIsValid && m_fileNameIsValid);
|
||||
}
|
||||
|
||||
void AddSeedDialog::OnPlatformSelectionChanged(const AzFramework::PlatformFlags& selectedPlatforms)
|
||||
{
|
||||
// Hide the "Create File" button if no platforms are selected
|
||||
m_platformIsValid = selectedPlatforms != AzFramework::PlatformFlags::Platform_NONE;
|
||||
m_ui->addSeedButton->setEnabled(m_platformIsValid && m_fileNameIsValid);
|
||||
}
|
||||
|
||||
void AddSeedDialog::FormatRelativePathString(QString& relativePath)
|
||||
{
|
||||
if (relativePath.startsWith(QtRelativePathPrefix))
|
||||
{
|
||||
relativePath.remove(0, static_cast<int>(strlen(QtRelativePathPrefix)));
|
||||
}
|
||||
}
|
||||
|
||||
} //namespace AssetBundler
|
||||
|
||||
#include <source/ui/moc_AddSeedDialog.cpp>
|
||||
@@ -0,0 +1,58 @@
|
||||
/*
|
||||
* 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.
|
||||
*
|
||||
*/
|
||||
#pragma once
|
||||
|
||||
#if !defined(Q_MOC_RUN)
|
||||
#include <AzCore/std/string/string.h>
|
||||
#include <AzFramework/Platform/PlatformDefaults.h>
|
||||
|
||||
#include <QDialog>
|
||||
#include <QSharedPointer>
|
||||
#endif
|
||||
|
||||
namespace Ui
|
||||
{
|
||||
class AddSeedDialog;
|
||||
}
|
||||
|
||||
namespace AssetBundler
|
||||
{
|
||||
class GUIApplicationManager;
|
||||
|
||||
class AddSeedDialog
|
||||
: public QDialog
|
||||
{
|
||||
Q_OBJECT
|
||||
|
||||
public:
|
||||
explicit AddSeedDialog(QWidget* parent, const AzFramework::PlatformFlags& enabledPlatforms, const AZStd::string& platformSpecificCachePath);
|
||||
virtual ~AddSeedDialog() {}
|
||||
|
||||
AZStd::string GetFileName();
|
||||
AzFramework::PlatformFlags GetPlatformFlags();
|
||||
|
||||
private:
|
||||
void OnBrowseFileButtonPressed();
|
||||
void OnPlatformSelectionChanged(const AzFramework::PlatformFlags& selectedPlatforms);
|
||||
|
||||
void FormatRelativePathString(QString& relativePath);
|
||||
|
||||
QSharedPointer<Ui::AddSeedDialog> m_ui;
|
||||
QString m_platformSpecificCachePath;
|
||||
bool m_isAddSeedDialog = false;
|
||||
|
||||
AZStd::string m_fileName;
|
||||
|
||||
bool m_fileNameIsValid = false;
|
||||
bool m_platformIsValid = false;
|
||||
};
|
||||
} // namespace AssetBundler
|
||||
@@ -0,0 +1,185 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<ui version="4.0">
|
||||
<class>AddSeedDialog</class>
|
||||
<widget class="QDialog" name="AddSeedDialog">
|
||||
<property name="windowModality">
|
||||
<enum>Qt::ApplicationModal</enum>
|
||||
</property>
|
||||
<property name="geometry">
|
||||
<rect>
|
||||
<x>0</x>
|
||||
<y>0</y>
|
||||
<width>450</width>
|
||||
<height>108</height>
|
||||
</rect>
|
||||
</property>
|
||||
<property name="sizePolicy">
|
||||
<sizepolicy hsizetype="MinimumExpanding" vsizetype="MinimumExpanding">
|
||||
<horstretch>0</horstretch>
|
||||
<verstretch>0</verstretch>
|
||||
</sizepolicy>
|
||||
</property>
|
||||
<property name="minimumSize">
|
||||
<size>
|
||||
<width>450</width>
|
||||
<height>0</height>
|
||||
</size>
|
||||
</property>
|
||||
<property name="windowTitle">
|
||||
<string>Add Seed Asset</string>
|
||||
</property>
|
||||
<property name="modal">
|
||||
<bool>true</bool>
|
||||
</property>
|
||||
<layout class="QVBoxLayout" name="verticalLayout_5">
|
||||
<property name="leftMargin">
|
||||
<number>0</number>
|
||||
</property>
|
||||
<property name="topMargin">
|
||||
<number>0</number>
|
||||
</property>
|
||||
<property name="rightMargin">
|
||||
<number>0</number>
|
||||
</property>
|
||||
<property name="bottomMargin">
|
||||
<number>0</number>
|
||||
</property>
|
||||
<item>
|
||||
<widget class="QFrame" name="inputValuesFrame">
|
||||
<property name="frameShape">
|
||||
<enum>QFrame::StyledPanel</enum>
|
||||
</property>
|
||||
<property name="frameShadow">
|
||||
<enum>QFrame::Raised</enum>
|
||||
</property>
|
||||
<layout class="QVBoxLayout" name="verticalLayout">
|
||||
<property name="leftMargin">
|
||||
<number>0</number>
|
||||
</property>
|
||||
<property name="topMargin">
|
||||
<number>0</number>
|
||||
</property>
|
||||
<property name="rightMargin">
|
||||
<number>0</number>
|
||||
</property>
|
||||
<property name="bottomMargin">
|
||||
<number>0</number>
|
||||
</property>
|
||||
<item>
|
||||
<widget class="QLabel" name="fileNameLabel">
|
||||
<property name="text">
|
||||
<string>Select Seed Asset:</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<layout class="QHBoxLayout" name="horizontalLayout_2">
|
||||
<item>
|
||||
<widget class="QLineEdit" name="fileNameLineEdit">
|
||||
<property name="readOnly">
|
||||
<bool>true</bool>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QPushButton" name="browseFileButton">
|
||||
<property name="text">
|
||||
<string>Browse...</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
</layout>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QFrame" name="lineFrame">
|
||||
<property name="frameShape">
|
||||
<enum>QFrame::StyledPanel</enum>
|
||||
</property>
|
||||
<property name="frameShadow">
|
||||
<enum>QFrame::Raised</enum>
|
||||
</property>
|
||||
<layout class="QVBoxLayout" name="verticalLayout_2">
|
||||
<property name="leftMargin">
|
||||
<number>0</number>
|
||||
</property>
|
||||
<property name="topMargin">
|
||||
<number>0</number>
|
||||
</property>
|
||||
<property name="rightMargin">
|
||||
<number>0</number>
|
||||
</property>
|
||||
<property name="bottomMargin">
|
||||
<number>0</number>
|
||||
</property>
|
||||
<item>
|
||||
<widget class="Line" name="line">
|
||||
<property name="orientation">
|
||||
<enum>Qt::Horizontal</enum>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
</layout>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="AssetBundler::PlatformSelectionWidget" name="platformSelectionWidget" native="true"/>
|
||||
</item>
|
||||
</layout>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<layout class="QHBoxLayout" name="horizontalLayout">
|
||||
<property name="rightMargin">
|
||||
<number>10</number>
|
||||
</property>
|
||||
<property name="bottomMargin">
|
||||
<number>10</number>
|
||||
</property>
|
||||
<item>
|
||||
<spacer name="horizontalSpacer">
|
||||
<property name="orientation">
|
||||
<enum>Qt::Horizontal</enum>
|
||||
</property>
|
||||
<property name="sizeHint" stdset="0">
|
||||
<size>
|
||||
<width>40</width>
|
||||
<height>20</height>
|
||||
</size>
|
||||
</property>
|
||||
</spacer>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QPushButton" name="cancelButton">
|
||||
<property name="text">
|
||||
<string>Cancel</string>
|
||||
</property>
|
||||
<property name="default">
|
||||
<bool>false</bool>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QPushButton" name="addSeedButton">
|
||||
<property name="text">
|
||||
<string>Add Seed</string>
|
||||
</property>
|
||||
<property name="default">
|
||||
<bool>true</bool>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
</layout>
|
||||
</item>
|
||||
</layout>
|
||||
</widget>
|
||||
<customwidgets>
|
||||
<customwidget>
|
||||
<class>AssetBundler::PlatformSelectionWidget</class>
|
||||
<extends>QWidget</extends>
|
||||
<header location="global">source/ui/PlatformSelectionWidget.h</header>
|
||||
<container>1</container>
|
||||
</customwidget>
|
||||
</customwidgets>
|
||||
<resources/>
|
||||
<connections/>
|
||||
</ui>
|
||||
@@ -0,0 +1,370 @@
|
||||
/*
|
||||
* 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 <source/ui/AssetBundlerTabWidget.h>
|
||||
|
||||
#include <source/utils/GUIApplicationManager.h>
|
||||
#include <source/utils/utils.h>
|
||||
|
||||
#include <AzFramework/IO/LocalFileIO.h>
|
||||
#include <AzFramework/StringFunc/StringFunc.h>
|
||||
#include <AzQtComponents/Utilities/DesktopUtilities.h>
|
||||
|
||||
#include <QApplication>
|
||||
#include <QClipboard>
|
||||
#include <QHeaderView>
|
||||
#include <QJsonArray>
|
||||
#include <QJsonDocument>
|
||||
#include <QJsonObject>
|
||||
#include <QJsonValue>
|
||||
#include <QMenu>
|
||||
#include <QMessageBox>
|
||||
|
||||
namespace AssetBundler
|
||||
{
|
||||
const char AssetBundlerCommonSettingsFile[] = "AssetBundlerCommonSettings.json";
|
||||
const char AssetBundlerUserSettingsFile[] = "AssetBundlerUserSettings.json";
|
||||
|
||||
const char ScanPathsKey[] = "ScanPaths";
|
||||
|
||||
const QString AssetBundlingFileTypes[] =
|
||||
{
|
||||
"SeedLists",
|
||||
"AssetLists",
|
||||
"BundleSettings",
|
||||
"Bundles",
|
||||
"Rules"
|
||||
};
|
||||
|
||||
const int MarginSize = 10;
|
||||
|
||||
AssetBundlerTabWidget::AssetBundlerTabWidget(QWidget* parent, GUIApplicationManager* guiApplicationManager)
|
||||
: QWidget(parent)
|
||||
, m_guiApplicationManager(guiApplicationManager)
|
||||
{
|
||||
connect(m_guiApplicationManager, &GUIApplicationManager::UpdateTab, this, &AssetBundlerTabWidget::OnUpdateTab);
|
||||
connect(m_guiApplicationManager, &GUIApplicationManager::UpdateFiles, this, &AssetBundlerTabWidget::OnUpdateFiles);
|
||||
|
||||
QAction* deleteFileAction = new QAction(tr("Delete"), this);
|
||||
addAction(deleteFileAction);
|
||||
deleteFileAction->setShortcut(QKeySequence::Delete);
|
||||
connect(deleteFileAction, &QAction::triggered, this, &AssetBundlerTabWidget::OnDeleteSelectedFileRequested);
|
||||
}
|
||||
|
||||
AssetBundlerTabWidget::~AssetBundlerTabWidget()
|
||||
{
|
||||
m_guiApplicationManager = nullptr;
|
||||
}
|
||||
|
||||
void AssetBundlerTabWidget::Activate()
|
||||
{
|
||||
SetActiveProjectLabel(tr("Active Project: %1").arg(m_guiApplicationManager->GetCurrentProjectName().c_str()));
|
||||
|
||||
SetupContextMenu();
|
||||
Reload();
|
||||
|
||||
connect(GetFileTableView()->header(), &QHeaderView::sortIndicatorChanged, m_fileTableFilterModel.get(), &AssetBundlerFileTableFilterModel::sort);
|
||||
GetFileTableView()->header()->setSortIndicatorShown(true);
|
||||
// Setting this in descending order will ensure the most recent files are at the top
|
||||
GetFileTableView()->header()->setSortIndicator(GetFileTableModel()->GetTimeStampColumnIndex(), Qt::DescendingOrder);
|
||||
GetFileTableView()->setSortingEnabled(true);
|
||||
}
|
||||
|
||||
void AssetBundlerTabWidget::InitAssetBundlerSettings(const char* currentProjectFolderPath)
|
||||
{
|
||||
AZStd::string commonSettingsPath = GetAssetBundlerCommonSettingsFile(currentProjectFolderPath);
|
||||
if (!AZ::IO::FileIOBase::GetInstance()->Exists(commonSettingsPath.c_str()))
|
||||
{
|
||||
CreateEmptyAssetBundlerSettings(commonSettingsPath);
|
||||
}
|
||||
|
||||
AZStd::string userSettingsPath = GetAssetBundlerUserSettingsFile(currentProjectFolderPath);
|
||||
if (!AZ::IO::FileIOBase::GetInstance()->Exists(userSettingsPath.c_str()))
|
||||
{
|
||||
CreateEmptyAssetBundlerSettings(userSettingsPath);
|
||||
}
|
||||
}
|
||||
|
||||
void AssetBundlerTabWidget::OnFileTableContextMenuRequested(const QPoint& pos)
|
||||
{
|
||||
AZStd::string selectedFileAbsolutePath(GetFileTableModel()->GetFileAbsolutePath(GetSelectedFileTableIndex()));
|
||||
|
||||
QMenu* contextMenu = new QMenu(this);
|
||||
contextMenu->setToolTipsVisible(true);
|
||||
|
||||
bool arePathOperationsEnabled = !selectedFileAbsolutePath.empty();
|
||||
QString emptyPathToolTip(tr("This file is not present on-disk."));
|
||||
|
||||
QAction* action = contextMenu->addAction(AzQtComponents::fileBrowserActionName(), [=]()
|
||||
{
|
||||
AzQtComponents::ShowFileOnDesktop(selectedFileAbsolutePath.c_str());
|
||||
});
|
||||
if (arePathOperationsEnabled)
|
||||
{
|
||||
action->setToolTip(tr("Shows the location of this file on your computer"));
|
||||
}
|
||||
else
|
||||
{
|
||||
action->setToolTip(emptyPathToolTip);
|
||||
action->setEnabled(false);
|
||||
}
|
||||
|
||||
action = contextMenu->addAction(tr("Copy Path to Clipboard"), [=]()
|
||||
{
|
||||
QApplication::clipboard()->setText(QString(selectedFileAbsolutePath.c_str()));
|
||||
});
|
||||
if (arePathOperationsEnabled)
|
||||
{
|
||||
action->setToolTip(tr("Copies the absolute path of this file to your Clipboard"));
|
||||
}
|
||||
else
|
||||
{
|
||||
action->setToolTip(emptyPathToolTip);
|
||||
action->setEnabled(false);
|
||||
}
|
||||
|
||||
contextMenu->addSeparator();
|
||||
|
||||
// We can't use the same Delete action as the constructor because we need to modify a lot of values
|
||||
action = new QAction(tr("Delete"), this);
|
||||
action->setShortcutContext(Qt::WidgetWithChildrenShortcut);
|
||||
action->setShortcut(QKeySequence::Delete);
|
||||
connect(action, &QAction::triggered, this, &AssetBundlerTabWidget::OnDeleteSelectedFileRequested);
|
||||
if (arePathOperationsEnabled)
|
||||
{
|
||||
action->setToolTip(tr("Deletes the selected file from disk."));
|
||||
}
|
||||
else
|
||||
{
|
||||
action->setToolTip(emptyPathToolTip);
|
||||
action->setEnabled(false);
|
||||
}
|
||||
contextMenu->addAction(action);
|
||||
|
||||
contextMenu->exec(GetFileTableView()->mapToGlobal(pos));
|
||||
delete contextMenu;
|
||||
}
|
||||
|
||||
void AssetBundlerTabWidget::OnDeleteSelectedFileRequested()
|
||||
{
|
||||
AZStd::string selectedFileAbsolutePath(GetFileTableModel()->GetFileAbsolutePath(GetSelectedFileTableIndex()));
|
||||
if (selectedFileAbsolutePath.empty())
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
QString messageBoxText = QString(tr("Are you sure you would like to delete %1? \n\nThis will permanently delete the file.")).arg(QString(selectedFileAbsolutePath.c_str()));
|
||||
|
||||
QMessageBox::StandardButton confirmDeleteFileResult = QMessageBox::question(this, QString(tr("Delete %1")).arg(GetFileTypeDisplayName()), messageBoxText);
|
||||
if (confirmDeleteFileResult != QMessageBox::StandardButton::Yes)
|
||||
{
|
||||
// User canceled out of the confirmation dialog
|
||||
return;
|
||||
}
|
||||
|
||||
if (GetFileTableModel()->DeleteFile(GetSelectedFileTableIndex()))
|
||||
{
|
||||
RemoveScanPathFromAssetBundlerSettings(GetFileType(), selectedFileAbsolutePath.c_str());
|
||||
}
|
||||
}
|
||||
|
||||
void AssetBundlerTabWidget::ReadScanPathsFromAssetBundlerSettings(AssetBundlingFileType fileType)
|
||||
{
|
||||
AZStd::string currentProjectFolderPath = m_guiApplicationManager->GetCurrentProjectFolder();
|
||||
ReadAssetBundlerSettings(GetAssetBundlerUserSettingsFile(currentProjectFolderPath.c_str()), fileType);
|
||||
ReadAssetBundlerSettings(GetAssetBundlerCommonSettingsFile(currentProjectFolderPath.c_str()), fileType);
|
||||
}
|
||||
|
||||
void AssetBundlerTabWidget::AddScanPathToAssetBundlerSettings(AssetBundlingFileType fileType, AZStd::string filePath)
|
||||
{
|
||||
AZStd::string defaultFolderPath;
|
||||
switch (fileType)
|
||||
{
|
||||
case AssetBundlingFileType::SeedListFileType:
|
||||
defaultFolderPath = m_guiApplicationManager->GetSeedListsFolder();
|
||||
break;
|
||||
case AssetBundlingFileType::AssetListFileType:
|
||||
defaultFolderPath = m_guiApplicationManager->GetAssetListsFolder();
|
||||
break;
|
||||
case AssetBundlingFileType::RulesFileType:
|
||||
defaultFolderPath = m_guiApplicationManager->GetRulesFolder();
|
||||
break;
|
||||
case AssetBundlingFileType::BundleSettingsFileType:
|
||||
defaultFolderPath = m_guiApplicationManager->GetBundleSettingsFolder();
|
||||
break;
|
||||
case AssetBundlingFileType::BundleFileType:
|
||||
defaultFolderPath = m_guiApplicationManager->GetBundlesFolder();
|
||||
break;
|
||||
default:
|
||||
AZ_Warning(AssetBundler::AppWindowName, false, "No default folder is defined for AssetBundlingFileType ( %i ).", static_cast<int>(fileType));
|
||||
break;
|
||||
}
|
||||
|
||||
AzFramework::StringFunc::Path::Normalize(filePath);
|
||||
AzFramework::StringFunc::Path::Normalize(defaultFolderPath);
|
||||
|
||||
if (AzFramework::StringFunc::StartsWith(filePath, defaultFolderPath))
|
||||
{
|
||||
// file is already in a watched folder, no need to add it to the settings file
|
||||
return;
|
||||
}
|
||||
|
||||
AddScanPathToAssetBundlerSettings(fileType, QString(filePath.c_str()));
|
||||
}
|
||||
|
||||
void AssetBundlerTabWidget::AddScanPathToAssetBundlerSettings(AssetBundlingFileType fileType, const QString& filePath)
|
||||
{
|
||||
AZStd::string assetBundlerSettingsFileAbsolutePath = GetAssetBundlerUserSettingsFile(m_guiApplicationManager->GetCurrentProjectFolder().c_str());
|
||||
QJsonObject assetBundlerSettings = AssetBundler::ReadJson(assetBundlerSettingsFileAbsolutePath);
|
||||
QJsonObject scanPathsSettings = assetBundlerSettings[ScanPathsKey].toObject();
|
||||
QJsonArray scanPaths = scanPathsSettings[AssetBundlingFileTypes[fileType]].toArray();
|
||||
|
||||
QFileInfo inputFileInfo(filePath);
|
||||
|
||||
for (const QJsonValue scanPath : m_watchedFiles + m_watchedFolders)
|
||||
{
|
||||
AZStd::string scanFilePathStr = scanPath.toString().toUtf8().data();
|
||||
AzFramework::StringFunc::Path::ConstructFull(GetCachedEngineRoot().c_str(), scanFilePathStr.c_str(), scanFilePathStr);
|
||||
|
||||
// Check whether the file has already been watched
|
||||
// Get absolute file paths via QFileInfo to keep consistency in the letter case
|
||||
if (inputFileInfo.absoluteFilePath().startsWith(
|
||||
QFileInfo(scanFilePathStr.c_str()).absoluteFilePath()))
|
||||
{
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
scanPaths.push_back(filePath);
|
||||
scanPathsSettings[AssetBundlingFileTypes[fileType]] = scanPaths;
|
||||
assetBundlerSettings[ScanPathsKey] = scanPathsSettings;
|
||||
AssetBundler::SaveJson(assetBundlerSettingsFileAbsolutePath, assetBundlerSettings);
|
||||
|
||||
m_watchedFiles.insert(filePath);
|
||||
m_guiApplicationManager->AddWatchedPath(filePath);
|
||||
}
|
||||
|
||||
void AssetBundlerTabWidget::RemoveScanPathFromAssetBundlerSettings(AssetBundlingFileType fileType, const QString& filePath)
|
||||
{
|
||||
AZStd::string assetBundlerSettingsFileAbsolutePath = GetAssetBundlerUserSettingsFile(m_guiApplicationManager->GetCurrentProjectFolder().c_str());
|
||||
QJsonObject assetBundlerSettings = AssetBundler::ReadJson(assetBundlerSettingsFileAbsolutePath);
|
||||
QJsonObject scanPathsSettings = assetBundlerSettings[ScanPathsKey].toObject();
|
||||
QJsonArray scanPaths = scanPathsSettings[AssetBundlingFileTypes[fileType]].toArray();
|
||||
|
||||
for (auto itr = scanPaths.begin(); itr != scanPaths.end(); ++itr)
|
||||
{
|
||||
QJsonValueRef scanPathValueRef = *itr;
|
||||
AZStd::string scanPath = scanPathValueRef.toString().toUtf8().data();
|
||||
AzFramework::StringFunc::Path::ConstructFull(GetCachedEngineRoot().c_str(), scanPath.c_str(), scanPath);
|
||||
|
||||
// Check whether the file is being watched
|
||||
// Get absolute file paths via QFileInfo to keep consistency in the letter case
|
||||
if (QFileInfo(filePath).absoluteFilePath() == QFileInfo(scanPath.c_str()).absoluteFilePath())
|
||||
{
|
||||
itr = scanPaths.erase(itr);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
scanPathsSettings[AssetBundlingFileTypes[fileType]] = scanPaths;
|
||||
assetBundlerSettings[ScanPathsKey] = scanPathsSettings;
|
||||
AssetBundler::SaveJson(assetBundlerSettingsFileAbsolutePath, assetBundlerSettings);
|
||||
|
||||
m_guiApplicationManager->RemoveWatchedPath(filePath);
|
||||
}
|
||||
|
||||
void AssetBundlerTabWidget::OnUpdateTab(const AZStd::string& path)
|
||||
{
|
||||
if (m_watchedFolders.contains(path.c_str()) ||
|
||||
m_watchedFiles.contains(path.c_str()))
|
||||
{
|
||||
Reload();
|
||||
}
|
||||
}
|
||||
|
||||
void AssetBundlerTabWidget::OnUpdateFiles(AssetBundlingFileType fileType, const AZStd::vector<AZStd::string>& absoluteFilePaths)
|
||||
{
|
||||
if (fileType == GetFileType())
|
||||
{
|
||||
GetFileTableModel()->ReloadFiles(absoluteFilePaths, m_filePathToGemNameMap);
|
||||
m_fileTableFilterModel->sort(m_fileTableFilterModel->sortColumn(), m_fileTableFilterModel->sortOrder());
|
||||
FileSelectionChanged();
|
||||
}
|
||||
}
|
||||
|
||||
void AssetBundlerTabWidget::SetupContextMenu()
|
||||
{
|
||||
GetFileTableView()->setContextMenuPolicy(Qt::CustomContextMenu);
|
||||
connect(GetFileTableView(), &QTreeView::customContextMenuRequested, this, &AssetBundlerTabWidget::OnFileTableContextMenuRequested);
|
||||
}
|
||||
|
||||
void AssetBundlerTabWidget::ReadAssetBundlerSettings(const AZStd::string& filePath, AssetBundlingFileType fileType)
|
||||
{
|
||||
// Read the config file which contains the customized scan paths information
|
||||
AZStd::vector<AZStd::string> assetBundlerSettingsFileList;
|
||||
QJsonObject assetBundlerSettings = AssetBundler::ReadJson(filePath);
|
||||
QJsonObject scanPaths = assetBundlerSettings.find(ScanPathsKey).value().toObject();
|
||||
|
||||
for (const QJsonValue scanPath : scanPaths[AssetBundlingFileTypes[fileType]].toArray())
|
||||
{
|
||||
AZStd::string absoluteScanPath = scanPath.toString().toUtf8().data();
|
||||
AZStd::replace(absoluteScanPath.begin(), absoluteScanPath.end(), AZ_WRONG_FILESYSTEM_SEPARATOR, AZ_CORRECT_FILESYSTEM_SEPARATOR);
|
||||
|
||||
if (AzFramework::StringFunc::Path::IsRelative(absoluteScanPath.c_str()))
|
||||
{
|
||||
AzFramework::StringFunc::Path::ConstructFull(GetCachedEngineRoot().c_str(), absoluteScanPath.c_str(), absoluteScanPath);
|
||||
}
|
||||
|
||||
if (AZ::IO::FileIOBase::GetInstance()->IsDirectory(absoluteScanPath.c_str()))
|
||||
{
|
||||
// The path specified in the config file is a directory
|
||||
m_watchedFolders.insert(absoluteScanPath.c_str());
|
||||
}
|
||||
else if (AZ::IO::FileIOBase::GetInstance()->Exists(absoluteScanPath.c_str()))
|
||||
{
|
||||
// The path specified in the config file is a file
|
||||
m_watchedFiles.insert(absoluteScanPath.c_str());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
AZStd::string AssetBundlerTabWidget::GetAssetBundlerUserSettingsFile(const char* currentProjectFolderPath)
|
||||
{
|
||||
AZStd::string absoluteFilePath;
|
||||
AzFramework::StringFunc::Path::ConstructFull(currentProjectFolderPath, AssetBundlerUserSettingsFile, absoluteFilePath);
|
||||
return absoluteFilePath;
|
||||
}
|
||||
|
||||
AZStd::string AssetBundlerTabWidget::GetAssetBundlerCommonSettingsFile(const char* currentProjectFolderPath)
|
||||
{
|
||||
AZStd::string absoluteFilePath;
|
||||
AzFramework::StringFunc::Path::ConstructFull(currentProjectFolderPath, AssetBundlerCommonSettingsFile, absoluteFilePath);
|
||||
return absoluteFilePath;
|
||||
}
|
||||
|
||||
void AssetBundlerTabWidget::CreateEmptyAssetBundlerSettings(const AZStd::string& filePath)
|
||||
{
|
||||
QJsonObject assetBundlerSettings;
|
||||
QJsonObject scanPathSettings;
|
||||
|
||||
for (const auto& fileType : AssetBundlingFileTypes)
|
||||
{
|
||||
scanPathSettings.insert(fileType, QJsonArray());
|
||||
}
|
||||
|
||||
assetBundlerSettings.insert(ScanPathsKey, scanPathSettings);
|
||||
|
||||
AssetBundler::SaveJson(filePath, assetBundlerSettings);
|
||||
}
|
||||
|
||||
} // namespace AssetBundler
|
||||
#include <source/ui/moc_AssetBundlerTabWidget.cpp>
|
||||
@@ -0,0 +1,118 @@
|
||||
/*
|
||||
* 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.
|
||||
*
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#if !defined(Q_MOC_RUN)
|
||||
#include <source/models/AssetBundlerAbstractFileTableModel.h>
|
||||
#include <source/models/AssetBundlerFileTableFilterModel.h>
|
||||
|
||||
#include <source/utils/GUIApplicationManager.h>
|
||||
|
||||
#include <AzCore/Outcome/Outcome.h>
|
||||
#include <AzCore/std/containers/vector.h>
|
||||
#include <AzCore/std/string/string.h>
|
||||
#include <AzQtComponents/Components/Widgets/TableView.h>
|
||||
|
||||
#include <QLabel>
|
||||
#include <QWidget>
|
||||
#include <QItemSelection>
|
||||
#endif
|
||||
|
||||
namespace AssetBundler
|
||||
{
|
||||
// Keys for the corresponding scan path lists in the asset bundling settings file
|
||||
extern const QString AssetBundlingFileTypes[];
|
||||
|
||||
extern const int MarginSize;
|
||||
|
||||
class AssetBundlerTabWidget
|
||||
: public QWidget
|
||||
{
|
||||
Q_OBJECT
|
||||
|
||||
public:
|
||||
explicit AssetBundlerTabWidget(QWidget* parent, GUIApplicationManager* guiApplicationManager);
|
||||
virtual ~AssetBundlerTabWidget();
|
||||
|
||||
void Activate();
|
||||
|
||||
virtual QString GetTabTitle() = 0;
|
||||
|
||||
virtual QString GetFileTypeDisplayName() = 0;
|
||||
|
||||
virtual AssetBundlingFileType GetFileType() = 0;
|
||||
|
||||
virtual bool HasUnsavedChanges() = 0;
|
||||
|
||||
//! Reload all the files on display.
|
||||
virtual void Reload() = 0;
|
||||
|
||||
//! Saves the selected file to disk.
|
||||
//! @return true on successful save, or throws an error message and returns false on a failed save.
|
||||
virtual bool SaveCurrentSelection() = 0;
|
||||
|
||||
//! Saves all modified files to disk.
|
||||
//! @return true on successful save, or throws an error message and returns false on a failed save.
|
||||
virtual bool SaveAll() = 0;
|
||||
|
||||
//! Set watched folders and files for the model
|
||||
virtual void SetModelDataSource() = 0;
|
||||
|
||||
virtual AzQtComponents::TableView* GetFileTableView() = 0;
|
||||
|
||||
virtual QModelIndex GetSelectedFileTableIndex() = 0;
|
||||
|
||||
virtual AssetBundlerAbstractFileTableModel* GetFileTableModel() = 0;
|
||||
|
||||
virtual void SetActiveProjectLabel(const QString& labelText) = 0;
|
||||
|
||||
virtual void ApplyConfig() = 0;
|
||||
|
||||
virtual void FileSelectionChanged(const QItemSelection& /*selected*/ = QItemSelection(), const QItemSelection& /*deselected*/ = QItemSelection()) = 0;
|
||||
|
||||
static void InitAssetBundlerSettings(const char* currentProjectFolderPath);
|
||||
|
||||
void AddScanPathToAssetBundlerSettings(AssetBundlingFileType fileType, AZStd::string filePath);
|
||||
|
||||
GUIApplicationManager* GetGUIApplicationManager() { return m_guiApplicationManager; }
|
||||
|
||||
protected:
|
||||
void OnFileTableContextMenuRequested(const QPoint& pos);
|
||||
//! Asks the user to confirm they wish to permanently delete the selected file, then removes it from disk and memory.
|
||||
void OnDeleteSelectedFileRequested();
|
||||
bool ConfirmFileDeleteDialog(const QString& absoluteFilePath);
|
||||
void ReadScanPathsFromAssetBundlerSettings(AssetBundlingFileType fileType);
|
||||
void RemoveScanPathFromAssetBundlerSettings(AssetBundlingFileType fileType, const QString& filePath);
|
||||
|
||||
GUIApplicationManager* m_guiApplicationManager = nullptr;
|
||||
QScopedPointer<AssetBundler::AssetBundlerFileTableFilterModel> m_fileTableFilterModel;
|
||||
|
||||
QSet<QString> m_watchedFolders;
|
||||
QSet<QString> m_watchedFiles;
|
||||
AZStd::unordered_map<AZStd::string, AZStd::string> m_filePathToGemNameMap;
|
||||
|
||||
private slots:
|
||||
void OnUpdateTab(const AZStd::string& path);
|
||||
void OnUpdateFiles(AssetBundlingFileType fileType, const AZStd::vector<AZStd::string>& absoluteFilePaths);
|
||||
|
||||
private:
|
||||
void SetupContextMenu();
|
||||
void AddScanPathToAssetBundlerSettings(AssetBundlingFileType fileType, const QString& filePath);
|
||||
void ReadAssetBundlerSettings(const AZStd::string& filePath, AssetBundlingFileType fileType);
|
||||
|
||||
static AZStd::string GetAssetBundlerUserSettingsFile(const char* currentProjectFolderPath);
|
||||
static AZStd::string GetAssetBundlerCommonSettingsFile(const char* currentProjectFolderPath);
|
||||
static void CreateEmptyAssetBundlerSettings(const AZStd::string& filePath);
|
||||
};
|
||||
|
||||
} // namespace AssetBundler
|
||||
@@ -0,0 +1,182 @@
|
||||
/*
|
||||
* 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 <source/ui/AssetListTabWidget.h>
|
||||
#include <source/ui/ui_AssetListTabWidget.h>
|
||||
|
||||
#include <source/utils/GUIApplicationManager.h>
|
||||
#include <source/ui/GenerateBundlesModal.h>
|
||||
#include <source/ui/NewFileDialog.h>
|
||||
#include <source/models/AssetListFileTableModel.h>
|
||||
#include <source/models/AssetListTableModel.h>
|
||||
|
||||
#include <AzCore/Outcome/Outcome.h>
|
||||
#include <AzFramework/StringFunc/StringFunc.h>
|
||||
#include <AzQtComponents/Components/FilteredSearchWidget.h>
|
||||
#include <AzQtComponents/Components/Widgets/TableView.h>
|
||||
#include <AzToolsFramework/Asset/AssetSeedManager.h>
|
||||
#include <AzToolsFramework/AssetCatalog/PlatformAddressedAssetCatalog.h>
|
||||
|
||||
#include <QItemSelection>
|
||||
#include <QItemSelectionRange>
|
||||
#include <QMessageBox>
|
||||
#include <QPushButton>
|
||||
|
||||
namespace AssetBundler
|
||||
{
|
||||
AssetListTabWidget::AssetListTabWidget(QWidget* parent, GUIApplicationManager* guiApplicationManager)
|
||||
: AssetBundlerTabWidget(parent, guiApplicationManager)
|
||||
, m_fileTableModel(new AssetListFileTableModel())
|
||||
, m_assetListContentsModel(new AssetListTableModel())
|
||||
{
|
||||
m_ui.reset(new Ui::AssetListTabWidget);
|
||||
m_ui->setupUi(this);
|
||||
|
||||
m_ui->mainVerticalLayout->setContentsMargins(10, 10, 10, 10);
|
||||
|
||||
// File view of all Asset List Files
|
||||
m_fileTableFilterModel.reset(new AssetBundlerFileTableFilterModel(this, m_fileTableModel->GetFileNameColumnIndex(), m_fileTableModel->GetTimeStampColumnIndex()));
|
||||
|
||||
m_fileTableFilterModel->setSourceModel(m_fileTableModel.data());
|
||||
m_ui->assetListsTable->setModel(m_fileTableFilterModel.data());
|
||||
connect(m_ui->fileFilteredSearchWidget, &AzQtComponents::FilteredSearchWidget::TextFilterChanged,
|
||||
m_fileTableFilterModel.data(), static_cast<void (QSortFilterProxyModel::*)(const QString&)>(&AssetBundlerFileTableFilterModel::FilterChanged));
|
||||
|
||||
connect(m_ui->assetListsTable->selectionModel(), &QItemSelectionModel::selectionChanged, this, &AssetListTabWidget::FileSelectionChanged);
|
||||
|
||||
m_ui->fileTableHeaderLayout->setContentsMargins(0, 0, 0, 0);
|
||||
m_ui->fileTableVerticalLayout->setContentsMargins(0, 0, 0, 0);
|
||||
m_ui->assetListsTable->setIndentation(0);
|
||||
|
||||
// Generate Bundle Button
|
||||
m_ui->generateBundleButton->setDefault(true);
|
||||
m_ui->generateBundleButton->setEnabled(false);
|
||||
connect(m_ui->generateBundleButton, &QPushButton::clicked, this, &AssetListTabWidget::OnGenerateBundleButtonPressed);
|
||||
|
||||
// Absolute path of selected Asset List file
|
||||
m_ui->assetListFileAbsolutePathLabel->setTextInteractionFlags(Qt::TextSelectableByMouse);
|
||||
|
||||
// Table that displays the contents of an Asset List File
|
||||
m_assetListContentsFilterModel.reset(new AssetBundlerFileTableFilterModel(this, AssetListTableModel::Column::ColumnAssetName));
|
||||
|
||||
m_assetListContentsFilterModel->setSourceModel(m_assetListContentsModel.data());
|
||||
m_ui->assetListContentsTable->setModel(m_assetListContentsFilterModel.data());
|
||||
connect(m_ui->assetListContentsFilteredSearchWidget, &AzQtComponents::FilteredSearchWidget::TextFilterChanged,
|
||||
m_assetListContentsFilterModel.data(), static_cast<void (QSortFilterProxyModel::*)(const QString&)>(&AssetBundlerFileTableFilterModel::FilterChanged));
|
||||
|
||||
|
||||
m_ui->fileContentsHeaderLayout->setContentsMargins(0, 0, 0, 0);
|
||||
m_ui->fileContentsVerticalLayout->setContentsMargins(0, 0, 0, 0);
|
||||
m_ui->assetListContentsTable->setIndentation(0);
|
||||
|
||||
SetModelDataSource();
|
||||
}
|
||||
|
||||
void AssetListTabWidget::SetModelDataSource()
|
||||
{
|
||||
// Remove the current watched folders and files
|
||||
m_guiApplicationManager->RemoveWatchedPaths(m_watchedFolders + m_watchedFiles);
|
||||
|
||||
// Set the new watched folder for the model
|
||||
m_watchedFolders.clear();
|
||||
m_watchedFiles.clear();
|
||||
m_watchedFolders.insert(m_guiApplicationManager->GetAssetListsFolder().c_str());
|
||||
ReadScanPathsFromAssetBundlerSettings(AssetBundlingFileType::AssetListFileType);
|
||||
|
||||
m_guiApplicationManager->AddWatchedPaths(m_watchedFolders + m_watchedFiles);
|
||||
}
|
||||
|
||||
AzQtComponents::TableView* AssetListTabWidget::GetFileTableView()
|
||||
{
|
||||
return m_ui->assetListsTable;
|
||||
}
|
||||
|
||||
QModelIndex AssetListTabWidget::GetSelectedFileTableIndex()
|
||||
{
|
||||
return m_selectedFileTableIndex;
|
||||
}
|
||||
|
||||
AssetBundlerAbstractFileTableModel* AssetListTabWidget::GetFileTableModel()
|
||||
{
|
||||
return m_fileTableModel.get();
|
||||
}
|
||||
|
||||
void AssetListTabWidget::SetActiveProjectLabel(const QString& labelText)
|
||||
{
|
||||
m_ui->activeProjectLabel->setText(labelText);
|
||||
}
|
||||
|
||||
void AssetListTabWidget::ApplyConfig()
|
||||
{
|
||||
const GUIApplicationManager::Config& config = m_guiApplicationManager->GetConfig();
|
||||
|
||||
m_ui->fileTableFrame->setFixedWidth(config.fileTableWidth);
|
||||
|
||||
m_ui->assetListsTable->header()->resizeSection(AssetListFileTableModel::Column::ColumnFileName, config.assetListFileNameColumnWidth);
|
||||
m_ui->assetListsTable->header()->resizeSection(AssetListFileTableModel::Column::ColumnPlatform, config.assetListPlatformColumnWidth);
|
||||
|
||||
m_ui->assetListContentsFilteredSearchWidget->setFixedWidth(config.fileTableWidth);
|
||||
|
||||
m_ui->assetListContentsTable->header()->resizeSection(AssetListTableModel::Column::ColumnAssetName, config.productAssetNameColumnWidth);
|
||||
m_ui->assetListContentsTable->header()->resizeSection(AssetListTableModel::Column::ColumnRelativePath, config.productAssetRelativePathColumnWidth);
|
||||
}
|
||||
|
||||
|
||||
void AssetListTabWidget::Reload()
|
||||
{
|
||||
// Reload all the asset list files
|
||||
m_fileTableModel->Reload(AzToolsFramework::AssetSeedManager::GetAssetListFileExtension(), m_watchedFolders, m_watchedFiles);
|
||||
|
||||
// Update the selected row
|
||||
FileSelectionChanged();
|
||||
}
|
||||
|
||||
void AssetListTabWidget::FileSelectionChanged(const QItemSelection& selected, const QItemSelection& deselected)
|
||||
{
|
||||
AZ_UNUSED(selected);
|
||||
AZ_UNUSED(deselected);
|
||||
|
||||
if (m_ui->assetListsTable->selectionModel()->selectedRows().size() == 0)
|
||||
{
|
||||
// Set selected index to an invalid value
|
||||
m_selectedFileTableIndex = QModelIndex();
|
||||
m_ui->assetListFileAbsolutePathLabel->setText("");
|
||||
m_assetListContentsModel.reset(new AssetListTableModel());
|
||||
m_assetListContentsFilterModel->setSourceModel(m_assetListContentsModel.data());
|
||||
m_ui->generateBundleButton->setEnabled(false);
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
m_selectedFileTableIndex = m_fileTableFilterModel->mapToSource(m_ui->assetListsTable->selectionModel()->currentIndex());
|
||||
|
||||
m_ui->assetListFileAbsolutePathLabel->setText(QString(m_fileTableModel->GetFileAbsolutePath(m_selectedFileTableIndex).c_str()));
|
||||
|
||||
m_assetListContentsModel = m_fileTableModel->GetAssetListFileContents(m_selectedFileTableIndex);
|
||||
m_assetListContentsFilterModel->setSourceModel(m_assetListContentsModel.data());
|
||||
|
||||
m_ui->generateBundleButton->setEnabled(true);
|
||||
}
|
||||
|
||||
void AssetListTabWidget::OnGenerateBundleButtonPressed()
|
||||
{
|
||||
GenerateBundlesModal generateBundlesModal(
|
||||
this,
|
||||
m_fileTableModel->GetFileAbsolutePath(m_selectedFileTableIndex),
|
||||
m_guiApplicationManager->GetBundlesFolder(),
|
||||
m_guiApplicationManager->GetBundleSettingsFolder(),
|
||||
this);
|
||||
generateBundlesModal.exec();
|
||||
}
|
||||
} //namespace AssetBundler
|
||||
|
||||
#include <source/ui/moc_AssetListTabWidget.cpp>
|
||||
@@ -0,0 +1,82 @@
|
||||
/*
|
||||
* 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.
|
||||
*
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#if !defined(Q_MOC_RUN)
|
||||
#include <source/ui/AssetBundlerTabWidget.h>
|
||||
|
||||
#include <AzCore/std/smart_ptr/unique_ptr.h>
|
||||
#include <AzFramework/Platform/PlatformDefaults.h>
|
||||
|
||||
#include <QDir>
|
||||
#include <QItemSelectionModel>
|
||||
#include <QModelIndex>
|
||||
#include <QSharedPointer>
|
||||
#include <QString>
|
||||
#include <QWidget>
|
||||
#endif
|
||||
|
||||
namespace Ui
|
||||
{
|
||||
class AssetListTabWidget;
|
||||
}
|
||||
|
||||
class QFileSystemModel;
|
||||
class QStringListModel;
|
||||
|
||||
namespace AssetBundler
|
||||
{
|
||||
class GUIApplicationManager;
|
||||
|
||||
class AssetListFileTableModel;
|
||||
class AssetListTableModel;
|
||||
|
||||
class AssetListTabWidget
|
||||
: public AssetBundlerTabWidget
|
||||
{
|
||||
Q_OBJECT
|
||||
|
||||
public:
|
||||
explicit AssetListTabWidget(QWidget* parent, GUIApplicationManager* guiApplicationManager);
|
||||
virtual ~AssetListTabWidget() {}
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////
|
||||
// AssetBundlerTabWidget overrides
|
||||
QString GetTabTitle() override { return tr("Asset Lists"); }
|
||||
QString GetFileTypeDisplayName() override { return tr("Asset List file"); }
|
||||
AssetBundlingFileType GetFileType() override { return AssetBundlingFileType::AssetListFileType; }
|
||||
bool HasUnsavedChanges() override { return false; };
|
||||
void Reload() override;
|
||||
bool SaveCurrentSelection() override { return true; };
|
||||
bool SaveAll() override { return true; };
|
||||
void SetModelDataSource() override;
|
||||
AzQtComponents::TableView* GetFileTableView() override;
|
||||
QModelIndex GetSelectedFileTableIndex() override;
|
||||
AssetBundlerAbstractFileTableModel* GetFileTableModel() override;
|
||||
void SetActiveProjectLabel(const QString& labelText) override;
|
||||
void ApplyConfig() override;
|
||||
void FileSelectionChanged(const QItemSelection& /*selected*/ = QItemSelection(), const QItemSelection& /*deselected*/ = QItemSelection()) override;
|
||||
//////////////////////////////////////////////////////////////////////////
|
||||
|
||||
private:
|
||||
void OnGenerateBundleButtonPressed();
|
||||
|
||||
QSharedPointer<Ui::AssetListTabWidget> m_ui;
|
||||
|
||||
QSharedPointer<AssetListFileTableModel> m_fileTableModel;
|
||||
QModelIndex m_selectedFileTableIndex;
|
||||
|
||||
QSharedPointer<AssetBundler::AssetBundlerFileTableFilterModel> m_assetListContentsFilterModel;
|
||||
QSharedPointer<AssetListTableModel> m_assetListContentsModel;
|
||||
};
|
||||
} // namespace AssetBundler
|
||||
@@ -0,0 +1,168 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<ui version="4.0">
|
||||
<class>AssetListTabWidget</class>
|
||||
<widget class="QWidget" name="AssetListTabWidget">
|
||||
<property name="geometry">
|
||||
<rect>
|
||||
<x>0</x>
|
||||
<y>0</y>
|
||||
<width>813</width>
|
||||
<height>673</height>
|
||||
</rect>
|
||||
</property>
|
||||
<property name="windowTitle">
|
||||
<string>Asset List Tab Widget</string>
|
||||
</property>
|
||||
<layout class="QVBoxLayout" name="mainVerticalLayout">
|
||||
<item>
|
||||
<layout class="QHBoxLayout" name="projectLabelHorizontalLayout">
|
||||
<item>
|
||||
<widget class="QLabel" name="activeProjectLabel"/>
|
||||
</item>
|
||||
<item>
|
||||
<spacer name="horizontalSpacer_3">
|
||||
<property name="orientation">
|
||||
<enum>Qt::Horizontal</enum>
|
||||
</property>
|
||||
<property name="sizeHint" stdset="0">
|
||||
<size>
|
||||
<width>40</width>
|
||||
<height>20</height>
|
||||
</size>
|
||||
</property>
|
||||
</spacer>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QPushButton" name="generateBundleButton">
|
||||
<property name="text">
|
||||
<string>Generate Bundle</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
</layout>
|
||||
</item>
|
||||
<item>
|
||||
<layout class="QHBoxLayout" name="horizontalLayout_4" stretch="0,0">
|
||||
<item>
|
||||
<widget class="QFrame" name="fileTableFrame">
|
||||
<property name="frameShape">
|
||||
<enum>QFrame::StyledPanel</enum>
|
||||
</property>
|
||||
<property name="frameShadow">
|
||||
<enum>QFrame::Raised</enum>
|
||||
</property>
|
||||
<layout class="QVBoxLayout" name="fileTableVerticalLayout">
|
||||
<item>
|
||||
<widget class="QFrame" name="fileTableHeaderFrame">
|
||||
<property name="frameShape">
|
||||
<enum>QFrame::StyledPanel</enum>
|
||||
</property>
|
||||
<property name="frameShadow">
|
||||
<enum>QFrame::Raised</enum>
|
||||
</property>
|
||||
<layout class="QVBoxLayout" name="fileTableHeaderLayout">
|
||||
<item>
|
||||
<widget class="QLabel" name="assetListFilesLabel">
|
||||
<property name="text">
|
||||
<string>Asset List Files</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
</layout>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="AzQtComponents::FilteredSearchWidget" name="fileFilteredSearchWidget">
|
||||
<property name="placeholderText" stdset="0">
|
||||
<string>Filter by file name</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="AzQtComponents::TableView" name="assetListsTable"/>
|
||||
</item>
|
||||
</layout>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QFrame" name="fileContentsFrame">
|
||||
<property name="frameShape">
|
||||
<enum>QFrame::StyledPanel</enum>
|
||||
</property>
|
||||
<property name="frameShadow">
|
||||
<enum>QFrame::Raised</enum>
|
||||
</property>
|
||||
<layout class="QVBoxLayout" name="fileContentsVerticalLayout">
|
||||
<item>
|
||||
<widget class="QFrame" name="fileContentsHeaderFrame">
|
||||
<property name="frameShape">
|
||||
<enum>QFrame::StyledPanel</enum>
|
||||
</property>
|
||||
<property name="frameShadow">
|
||||
<enum>QFrame::Raised</enum>
|
||||
</property>
|
||||
<layout class="QHBoxLayout" name="fileContentsHeaderLayout">
|
||||
<item>
|
||||
<widget class="QLabel" name="assetListContentsLabel">
|
||||
<property name="text">
|
||||
<string>Asset List</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QLabel" name="assetListFileAbsolutePathLabel">
|
||||
<property name="text">
|
||||
<string/>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<spacer name="horizontalSpacer">
|
||||
<property name="orientation">
|
||||
<enum>Qt::Horizontal</enum>
|
||||
</property>
|
||||
<property name="sizeHint" stdset="0">
|
||||
<size>
|
||||
<width>40</width>
|
||||
<height>20</height>
|
||||
</size>
|
||||
</property>
|
||||
</spacer>
|
||||
</item>
|
||||
</layout>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="AzQtComponents::FilteredSearchWidget" name="assetListContentsFilteredSearchWidget">
|
||||
<property name="placeholderText" stdset="0">
|
||||
<string>Filter by file name</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="AzQtComponents::TableView" name="assetListContentsTable"/>
|
||||
</item>
|
||||
</layout>
|
||||
</widget>
|
||||
</item>
|
||||
</layout>
|
||||
</item>
|
||||
</layout>
|
||||
</widget>
|
||||
<customwidgets>
|
||||
<customwidget>
|
||||
<class>AzQtComponents::TableView</class>
|
||||
<extends>QTreeView</extends>
|
||||
<header location="global">AzQtComponents/Components/Widgets/TableView.h</header>
|
||||
<container>1</container>
|
||||
</customwidget>
|
||||
<customwidget>
|
||||
<class>AzQtComponents::FilteredSearchWidget</class>
|
||||
<extends>QTreeView</extends>
|
||||
<header location="global">AzQtComponents/Components/FilteredSearchWidget.h</header>
|
||||
<container>1</container>
|
||||
</customwidget>
|
||||
</customwidgets>
|
||||
<resources/>
|
||||
<connections/>
|
||||
</ui>
|
||||
@@ -0,0 +1,159 @@
|
||||
/*
|
||||
* All or portions of this file Copyright(c) Amazon.com, Inc. or its affiliates or
|
||||
*its licensors.
|
||||
*
|
||||
* For complete copyrightand 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 <source/ui/BundleListTabWidget.h>
|
||||
#include <source/ui/ui_BundleListTabWidget.h>
|
||||
|
||||
#include <source/models/BundleFileListModel.h>
|
||||
#include <source/utils/GUIApplicationManager.h>
|
||||
|
||||
#include <AzQtComponents/Components/FilteredSearchWidget.h>
|
||||
|
||||
#include <QFileDialog>
|
||||
#include <QItemSelectionModel>
|
||||
|
||||
const double BytesToMegabytes = 1024.0 * 1024.0;
|
||||
|
||||
namespace AssetBundler
|
||||
{
|
||||
|
||||
BundleListTabWidget::BundleListTabWidget(QWidget* parent, GUIApplicationManager* guiApplicationManager)
|
||||
: AssetBundlerTabWidget(parent, guiApplicationManager)
|
||||
{
|
||||
m_ui.reset(new Ui::BundleListTabWidget);
|
||||
m_ui->setupUi(this);
|
||||
|
||||
m_ui->mainVerticalLayout->setContentsMargins(MarginSize, MarginSize, MarginSize, MarginSize);
|
||||
|
||||
m_fileTableModel.reset(new BundleFileListModel);
|
||||
m_fileTableFilterModel.reset(new AssetBundlerFileTableFilterModel(this, m_fileTableModel->GetFileNameColumnIndex(), m_fileTableModel->GetTimeStampColumnIndex()));
|
||||
|
||||
m_fileTableFilterModel->setSourceModel(m_fileTableModel.data());
|
||||
m_ui->fileTableView->setModel(m_fileTableFilterModel.data());
|
||||
connect(m_ui->fileFilteredSearchWidget, &AzQtComponents::FilteredSearchWidget::TextFilterChanged,
|
||||
m_fileTableFilterModel.data(), static_cast<void (QSortFilterProxyModel::*)(const QString&)>(&AssetBundlerFileTableFilterModel::FilterChanged));
|
||||
|
||||
connect(m_ui->fileTableView->selectionModel(), &QItemSelectionModel::selectionChanged, this, &BundleListTabWidget::FileSelectionChanged);
|
||||
|
||||
m_ui->fileTableView->setIndentation(0);
|
||||
|
||||
m_relatedBundlesListModel.reset(new QStringListModel);
|
||||
m_ui->relatedBundlesListView->setModel(m_relatedBundlesListModel.data());
|
||||
|
||||
m_ui->bundleFileContentsVerticalLayout->setContentsMargins(MarginSize, MarginSize, MarginSize, MarginSize);
|
||||
|
||||
SetModelDataSource();
|
||||
}
|
||||
|
||||
void BundleListTabWidget::Reload()
|
||||
{
|
||||
// The act of cracking open paks kicks off a DirectoryChanged event. We need to temporarily remove the Bundles
|
||||
// directory from our watched paths to prevent an infinite loop of events.
|
||||
m_guiApplicationManager->RemoveWatchedPaths(m_watchedFolders);
|
||||
|
||||
// Reload all the bundle files
|
||||
m_fileTableModel->Reload(AzToolsFramework::AssetBundleSettings::GetBundleFileExtension(), m_watchedFolders, m_watchedFiles);
|
||||
|
||||
// Update the selected row
|
||||
FileSelectionChanged();
|
||||
|
||||
// Start recieving DirectoryChanged events for these folders again
|
||||
m_guiApplicationManager->AddWatchedPaths(m_watchedFolders);
|
||||
}
|
||||
|
||||
void BundleListTabWidget::SetModelDataSource()
|
||||
{
|
||||
// Remove the current watched folders and files
|
||||
m_guiApplicationManager->RemoveWatchedPaths(m_watchedFolders + m_watchedFiles);
|
||||
|
||||
// Set the new watched folder for the model
|
||||
m_watchedFolders.clear();
|
||||
m_watchedFiles.clear();
|
||||
m_watchedFolders.insert(m_guiApplicationManager->GetBundlesFolder().c_str());
|
||||
ReadScanPathsFromAssetBundlerSettings(AssetBundlingFileType::BundleFileType);
|
||||
|
||||
m_guiApplicationManager->AddWatchedPaths(m_watchedFolders + m_watchedFiles);
|
||||
}
|
||||
|
||||
AzQtComponents::TableView* BundleListTabWidget::GetFileTableView()
|
||||
{
|
||||
return m_ui->fileTableView;
|
||||
}
|
||||
|
||||
QModelIndex BundleListTabWidget::GetSelectedFileTableIndex()
|
||||
{
|
||||
return m_selectedFileTableIndex;
|
||||
}
|
||||
|
||||
AssetBundlerAbstractFileTableModel* BundleListTabWidget::GetFileTableModel()
|
||||
{
|
||||
return m_fileTableModel.get();
|
||||
}
|
||||
|
||||
void BundleListTabWidget::SetActiveProjectLabel(const QString& labelText)
|
||||
{
|
||||
m_ui->activeProjectLabel->setText(labelText);
|
||||
}
|
||||
|
||||
void BundleListTabWidget::ApplyConfig()
|
||||
{
|
||||
const GUIApplicationManager::Config& config = m_guiApplicationManager->GetConfig();
|
||||
m_ui->fileTableFrame->setFixedWidth(config.fileTableWidth);
|
||||
m_ui->fileTableView->header()->resizeSection(BundleFileListModel::Column::ColumnFileName, config.fileNameColumnWidth);
|
||||
}
|
||||
|
||||
|
||||
void BundleListTabWidget::FileSelectionChanged(const QItemSelection& /*selected*/, const QItemSelection& /*deselected*/)
|
||||
{
|
||||
if (m_ui->fileTableView->selectionModel()->selectedRows().size() == 0)
|
||||
{
|
||||
m_selectedFileTableIndex = QModelIndex();
|
||||
ClearDisplayedBundleValues();
|
||||
return;
|
||||
}
|
||||
|
||||
m_selectedFileTableIndex = m_fileTableFilterModel->mapToSource(m_ui->fileTableView->selectionModel()->selectedRows()[0]);
|
||||
AZ::Outcome< BundleFileInfoPtr, void> fileInfoOutcome = m_fileTableModel->GetBundleInfo(m_selectedFileTableIndex);
|
||||
|
||||
if (!fileInfoOutcome.IsSuccess())
|
||||
{
|
||||
ClearDisplayedBundleValues();
|
||||
return;
|
||||
}
|
||||
|
||||
BundleFileInfoPtr fileInfoPtr = fileInfoOutcome.GetValue();
|
||||
|
||||
m_ui->absolutePathLabel->setText(fileInfoPtr->m_absolutePath.c_str());
|
||||
|
||||
QString sizeFormat("%1 MB");
|
||||
double compressedSize = (double)fileInfoPtr->m_compressedSize / BytesToMegabytes;
|
||||
m_ui->compressedSizeValueLabel->setText(sizeFormat.arg(compressedSize, 6, 'f', 3));
|
||||
|
||||
bool hasRelatedBundles = !fileInfoPtr->m_relatedBundles.isEmpty();
|
||||
if (hasRelatedBundles)
|
||||
{
|
||||
m_relatedBundlesListModel->setStringList(fileInfoPtr->m_relatedBundles);
|
||||
}
|
||||
m_ui->relatedBundlesLabel->setVisible(hasRelatedBundles);
|
||||
m_ui->relatedBundlesListView->setVisible(hasRelatedBundles);
|
||||
}
|
||||
|
||||
void BundleListTabWidget::ClearDisplayedBundleValues()
|
||||
{
|
||||
m_ui->absolutePathLabel->clear();
|
||||
m_ui->compressedSizeValueLabel->clear();
|
||||
m_ui->relatedBundlesLabel->setVisible(false);
|
||||
m_ui->relatedBundlesListView->setVisible(false);
|
||||
m_relatedBundlesListModel->setStringList({});
|
||||
}
|
||||
}
|
||||
|
||||
#include <source/ui/moc_BundleListTabWidget.cpp>
|
||||
@@ -0,0 +1,67 @@
|
||||
/*
|
||||
* 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.
|
||||
*
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#if !defined(Q_MOC_RUN)
|
||||
#include <source/ui/AssetBundlerTabWidget.h>
|
||||
|
||||
#include <QItemSelection>
|
||||
#include <QModelIndex>
|
||||
#include <QSharedPointer>
|
||||
#include <QString>
|
||||
#include <QStringListModel>
|
||||
#include <QWidget>
|
||||
#endif
|
||||
|
||||
namespace Ui
|
||||
{
|
||||
class BundleListTabWidget;
|
||||
}
|
||||
|
||||
namespace AssetBundler
|
||||
{
|
||||
class BundleFileListModel;
|
||||
|
||||
class BundleListTabWidget
|
||||
: public AssetBundlerTabWidget
|
||||
{
|
||||
Q_OBJECT
|
||||
public:
|
||||
explicit BundleListTabWidget(QWidget* parent, GUIApplicationManager* guiApplicationManager);
|
||||
virtual ~BundleListTabWidget() {}
|
||||
|
||||
QString GetTabTitle() override { return tr("Completed Bundles"); }
|
||||
QString GetFileTypeDisplayName() override { return tr("Bundle"); }
|
||||
AssetBundlingFileType GetFileType() override { return AssetBundlingFileType::BundleFileType; }
|
||||
bool HasUnsavedChanges() override { return false; }
|
||||
void Reload() override;
|
||||
bool SaveCurrentSelection() override { return true; }
|
||||
bool SaveAll() override { return true; }
|
||||
void SetModelDataSource() override;
|
||||
AzQtComponents::TableView* GetFileTableView() override;
|
||||
QModelIndex GetSelectedFileTableIndex() override;
|
||||
AssetBundlerAbstractFileTableModel* GetFileTableModel() override;
|
||||
void SetActiveProjectLabel(const QString& labelText) override;
|
||||
void ApplyConfig() override;
|
||||
void FileSelectionChanged(const QItemSelection& /*selected*/ = QItemSelection(), const QItemSelection& /*deselected*/ = QItemSelection()) override;
|
||||
|
||||
private:
|
||||
void ClearDisplayedBundleValues();
|
||||
|
||||
QSharedPointer<Ui::BundleListTabWidget> m_ui;
|
||||
QSharedPointer<BundleFileListModel> m_fileTableModel;
|
||||
QModelIndex m_selectedFileTableIndex;
|
||||
QSharedPointer<QStringListModel> m_relatedBundlesListModel;
|
||||
};
|
||||
|
||||
}
|
||||
@@ -0,0 +1,253 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<ui version="4.0">
|
||||
<class>BundleListTabWidget</class>
|
||||
<widget class="QWidget" name="BundleListTabWidget">
|
||||
<property name="geometry">
|
||||
<rect>
|
||||
<x>0</x>
|
||||
<y>0</y>
|
||||
<width>888</width>
|
||||
<height>562</height>
|
||||
</rect>
|
||||
</property>
|
||||
<property name="windowTitle">
|
||||
<string>Bundle List Tab Widget</string>
|
||||
</property>
|
||||
<layout class="QVBoxLayout" name="mainVerticalLayout">
|
||||
<property name="leftMargin">
|
||||
<number>0</number>
|
||||
</property>
|
||||
<property name="topMargin">
|
||||
<number>0</number>
|
||||
</property>
|
||||
<property name="rightMargin">
|
||||
<number>0</number>
|
||||
</property>
|
||||
<property name="bottomMargin">
|
||||
<number>0</number>
|
||||
</property>
|
||||
<item>
|
||||
<widget class="QLabel" name="activeProjectLabel"/>
|
||||
</item>
|
||||
<item>
|
||||
<layout class="QHBoxLayout" name="horizontalLayout_4" stretch="0,0">
|
||||
<item>
|
||||
<widget class="QFrame" name="fileTableFrame">
|
||||
<property name="frameShape">
|
||||
<enum>QFrame::StyledPanel</enum>
|
||||
</property>
|
||||
<property name="frameShadow">
|
||||
<enum>QFrame::Raised</enum>
|
||||
</property>
|
||||
<layout class="QVBoxLayout" name="verticalLayout_3">
|
||||
<property name="leftMargin">
|
||||
<number>0</number>
|
||||
</property>
|
||||
<property name="topMargin">
|
||||
<number>0</number>
|
||||
</property>
|
||||
<property name="rightMargin">
|
||||
<number>0</number>
|
||||
</property>
|
||||
<property name="bottomMargin">
|
||||
<number>0</number>
|
||||
</property>
|
||||
<item>
|
||||
<widget class="QFrame" name="fileTableHeaderFrame">
|
||||
<property name="frameShape">
|
||||
<enum>QFrame::StyledPanel</enum>
|
||||
</property>
|
||||
<property name="frameShadow">
|
||||
<enum>QFrame::Raised</enum>
|
||||
</property>
|
||||
<layout class="QVBoxLayout" name="verticalLayout_4">
|
||||
<property name="leftMargin">
|
||||
<number>0</number>
|
||||
</property>
|
||||
<property name="topMargin">
|
||||
<number>0</number>
|
||||
</property>
|
||||
<property name="rightMargin">
|
||||
<number>0</number>
|
||||
</property>
|
||||
<property name="bottomMargin">
|
||||
<number>0</number>
|
||||
</property>
|
||||
<item>
|
||||
<widget class="QLabel" name="bundleFilesLabel">
|
||||
<property name="text">
|
||||
<string>Bundles</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
</layout>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="AzQtComponents::FilteredSearchWidget" name="fileFilteredSearchWidget">
|
||||
<property name="placeholderText" stdset="0">
|
||||
<string>Filter by file name</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="AzQtComponents::TableView" name="fileTableView"/>
|
||||
</item>
|
||||
</layout>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QFrame" name="fileContentsFrame">
|
||||
<property name="frameShape">
|
||||
<enum>QFrame::StyledPanel</enum>
|
||||
</property>
|
||||
<property name="frameShadow">
|
||||
<enum>QFrame::Raised</enum>
|
||||
</property>
|
||||
<layout class="QVBoxLayout" name="verticalLayout_2">
|
||||
<property name="leftMargin">
|
||||
<number>0</number>
|
||||
</property>
|
||||
<property name="topMargin">
|
||||
<number>0</number>
|
||||
</property>
|
||||
<property name="rightMargin">
|
||||
<number>0</number>
|
||||
</property>
|
||||
<property name="bottomMargin">
|
||||
<number>0</number>
|
||||
</property>
|
||||
<item>
|
||||
<widget class="QFrame" name="fileContentsHeaderFrame">
|
||||
<property name="frameShape">
|
||||
<enum>QFrame::StyledPanel</enum>
|
||||
</property>
|
||||
<property name="frameShadow">
|
||||
<enum>QFrame::Raised</enum>
|
||||
</property>
|
||||
<layout class="QHBoxLayout" name="horizontalLayout_2">
|
||||
<property name="leftMargin">
|
||||
<number>0</number>
|
||||
</property>
|
||||
<property name="topMargin">
|
||||
<number>0</number>
|
||||
</property>
|
||||
<property name="rightMargin">
|
||||
<number>0</number>
|
||||
</property>
|
||||
<property name="bottomMargin">
|
||||
<number>0</number>
|
||||
</property>
|
||||
<item>
|
||||
<widget class="QLabel" name="bundleInfoLabel">
|
||||
<property name="text">
|
||||
<string>Bundle Info</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QLabel" name="absolutePathLabel">
|
||||
<property name="text">
|
||||
<string>TextLabel</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<spacer name="horizontalSpacer">
|
||||
<property name="orientation">
|
||||
<enum>Qt::Horizontal</enum>
|
||||
</property>
|
||||
<property name="sizeHint" stdset="0">
|
||||
<size>
|
||||
<width>40</width>
|
||||
<height>20</height>
|
||||
</size>
|
||||
</property>
|
||||
</spacer>
|
||||
</item>
|
||||
</layout>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QWidget" name="bundleFileContentsWidget" native="true">
|
||||
<layout class="QVBoxLayout" name="bundleFileContentsVerticalLayout">
|
||||
<property name="leftMargin">
|
||||
<number>0</number>
|
||||
</property>
|
||||
<property name="topMargin">
|
||||
<number>0</number>
|
||||
</property>
|
||||
<property name="rightMargin">
|
||||
<number>0</number>
|
||||
</property>
|
||||
<property name="bottomMargin">
|
||||
<number>0</number>
|
||||
</property>
|
||||
<item>
|
||||
<layout class="QFormLayout" name="bundleInfoLayout">
|
||||
<item row="0" column="0">
|
||||
<widget class="QLabel" name="compressedSizeLabel">
|
||||
<property name="text">
|
||||
<string>Compressed Size</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="0" column="1">
|
||||
<widget class="QLabel" name="compressedSizeValueLabel">
|
||||
<property name="text">
|
||||
<string>TextLabel</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="1" column="0">
|
||||
<widget class="QLabel" name="relatedBundlesLabel">
|
||||
<property name="text">
|
||||
<string>Related Bundles</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="1" column="1">
|
||||
<widget class="QListView" name="relatedBundlesListView"/>
|
||||
</item>
|
||||
</layout>
|
||||
</item>
|
||||
<item>
|
||||
<spacer name="verticalSpacer">
|
||||
<property name="orientation">
|
||||
<enum>Qt::Vertical</enum>
|
||||
</property>
|
||||
<property name="sizeHint" stdset="0">
|
||||
<size>
|
||||
<width>20</width>
|
||||
<height>40</height>
|
||||
</size>
|
||||
</property>
|
||||
</spacer>
|
||||
</item>
|
||||
</layout>
|
||||
</widget>
|
||||
</item>
|
||||
</layout>
|
||||
</widget>
|
||||
</item>
|
||||
</layout>
|
||||
</item>
|
||||
</layout>
|
||||
</widget>
|
||||
<customwidgets>
|
||||
<customwidget>
|
||||
<class>AzQtComponents::TableView</class>
|
||||
<extends>QTreeView</extends>
|
||||
<header location="global">AzQtComponents/Components/Widgets/TableView.h</header>
|
||||
<container>1</container>
|
||||
</customwidget>
|
||||
<customwidget>
|
||||
<class>AzQtComponents::FilteredSearchWidget</class>
|
||||
<extends>QTreeView</extends>
|
||||
<header location="global">AzQtComponents/Components/FilteredSearchWidget.h</header>
|
||||
<container>1</container>
|
||||
</customwidget>
|
||||
</customwidgets>
|
||||
<resources/>
|
||||
<connections/>
|
||||
</ui>
|
||||
@@ -0,0 +1,451 @@
|
||||
/*
|
||||
* 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 <source/ui/ComparisonDataWidget.h>
|
||||
#include <source/ui/ui_ComparisonDataWidget.h>
|
||||
|
||||
#include <source/ui/NewFileDialog.h>
|
||||
|
||||
#include <QComboBox>
|
||||
#include <QStringList>
|
||||
|
||||
namespace AssetBundler
|
||||
{
|
||||
//////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
// ComparisonDataWidget
|
||||
//////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
const QStringList ComparisonTypeStringList = { "Default", "Delta", "Union", "Intersection", "Complement", "Wildcard", "Regex" };
|
||||
|
||||
ComparisonDataWidget::ComparisonDataWidget(
|
||||
AZStd::shared_ptr<AzToolsFramework::AssetFileInfoListComparison> comparisonList,
|
||||
size_t comparisonDataIndex,
|
||||
const AZStd::string& defaultAssetListFileDirectory,
|
||||
QWidget* parent)
|
||||
: QWidget(parent)
|
||||
, m_comparisonDataIndex(comparisonDataIndex)
|
||||
, m_defaultAssetListFileDirectory(defaultAssetListFileDirectory)
|
||||
{
|
||||
m_ui.reset(new Ui::ComparisonDataWidget);
|
||||
m_ui->setupUi(this);
|
||||
|
||||
m_comparisonList = comparisonList;
|
||||
|
||||
if (!IsComparisonDataIndexValid())
|
||||
{
|
||||
AZ_Error("AssetBundler", false, "ComparisonData index ( %u ) is out of bounds. ComparisonData cannot be displayed.", m_comparisonDataIndex);
|
||||
return;
|
||||
}
|
||||
|
||||
// Due to initialization order, we need to hard-code this or else the value will be overwritten once this
|
||||
// ComparisonDataWidget is added to the ComparisonDataCard, and the Card.qss file is applied
|
||||
QString lineEditStyle("background-color: #CCCCCC;");
|
||||
m_ui->nameLineEdit->setStyleSheet(lineEditStyle);
|
||||
m_ui->firstInputLineEdit->setStyleSheet(lineEditStyle);
|
||||
m_ui->secondInputLineEdit->setStyleSheet(lineEditStyle);
|
||||
m_ui->filePatternLineEdit->setStyleSheet(lineEditStyle);
|
||||
|
||||
m_ui->firstInputLineEdit->setReadOnly(true);
|
||||
m_ui->secondInputLineEdit->setReadOnly(true);
|
||||
|
||||
SetAllDisplayValues(m_comparisonList->GetComparisonList()[m_comparisonDataIndex]);
|
||||
|
||||
MouseWheelEventFilter* mouseWheelEventFilter = new MouseWheelEventFilter(this);
|
||||
|
||||
connect(m_ui->nameLineEdit, &QLineEdit::textEdited, this, &ComparisonDataWidget::OnNameLineEditChanged);
|
||||
|
||||
m_ui->comparisonTypeComboBox->installEventFilter(mouseWheelEventFilter);
|
||||
connect(m_ui->comparisonTypeComboBox, QOverload<int>::of(&QComboBox::currentIndexChanged), this, &ComparisonDataWidget::OnComparisonTypeComboBoxChanged);
|
||||
|
||||
m_ui->firstInputComboBox->installEventFilter(mouseWheelEventFilter);
|
||||
connect(m_ui->firstInputComboBox, QOverload<int>::of(&QComboBox::currentIndexChanged), this, &ComparisonDataWidget::OnFirstInputComboBoxChanged);
|
||||
connect(m_ui->firstInputBrowseButton, &QPushButton::pressed, this, &ComparisonDataWidget::OnFirstInputBrowseButtonPressed);
|
||||
|
||||
m_ui->secondInputComboBox->installEventFilter(mouseWheelEventFilter);
|
||||
connect(m_ui->secondInputComboBox, QOverload<int>::of(&QComboBox::currentIndexChanged), this, &ComparisonDataWidget::OnSecondInputComboBoxChanged);
|
||||
connect(m_ui->secondInputBrowseButton, &QPushButton::pressed, this, &ComparisonDataWidget::OnSecondInputBrowseButtonPressed);
|
||||
|
||||
connect(m_ui->filePatternLineEdit, &QLineEdit::textEdited, this, &ComparisonDataWidget::OnFilePatternLineEditChanged);
|
||||
}
|
||||
|
||||
void ComparisonDataWidget::UpdateListOfTokenNames()
|
||||
{
|
||||
using namespace AzToolsFramework;
|
||||
|
||||
if (!IsComparisonDataIndexValid())
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
m_inputTokenNameList.clear();
|
||||
m_ui->firstInputComboBox->clear();
|
||||
m_ui->secondInputComboBox->clear();
|
||||
|
||||
// Store info about the current FirstInput and SecondInput values so we may auto-select them later
|
||||
auto allComparisonDataSteps = m_comparisonList->GetComparisonList();
|
||||
AZStd::string selectedFirstInput = allComparisonDataSteps.at(m_comparisonDataIndex).m_firstInput;
|
||||
int selectedFirstInputIndex = 0;
|
||||
AZStd::string selectedSecondInput = allComparisonDataSteps.at(m_comparisonDataIndex).m_secondInput;
|
||||
int selectedSecondInputIndex = 0;
|
||||
|
||||
// Build list of all Token Names that have come before the current Comparison Step
|
||||
m_inputTokenNameList.append(tr("Choose Asset List..."));
|
||||
int currentComboBoxIndex = 1;
|
||||
|
||||
AZStd::string tokenName;
|
||||
for (size_t i = 0; i < m_comparisonDataIndex; ++i)
|
||||
{
|
||||
tokenName = allComparisonDataSteps.at(i).m_output;
|
||||
if (!AssetFileInfoListComparison::IsTokenFile(tokenName))
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
if (tokenName == selectedFirstInput)
|
||||
{
|
||||
selectedFirstInputIndex = currentComboBoxIndex;
|
||||
}
|
||||
if (tokenName == selectedSecondInput)
|
||||
{
|
||||
selectedSecondInputIndex = currentComboBoxIndex;
|
||||
}
|
||||
|
||||
m_inputTokenNameList.append(RemoveTokenCharFromString(tokenName));
|
||||
++currentComboBoxIndex;
|
||||
}
|
||||
|
||||
// Update display with list of Token Names, and select current Token Name in both input combo boxes
|
||||
m_ui->firstInputComboBox->insertItems(0, m_inputTokenNameList);
|
||||
m_ui->firstInputComboBox->setCurrentIndex(selectedFirstInputIndex);
|
||||
m_isFirstInputFileNameVisible = selectedFirstInputIndex == 0;
|
||||
SetFirstInputFileVisibility(m_isFirstInputFileNameVisible);
|
||||
|
||||
m_ui->secondInputComboBox->insertItems(0, m_inputTokenNameList);
|
||||
m_ui->secondInputComboBox->setCurrentIndex(selectedSecondInputIndex);
|
||||
m_isSecondInputFileNameVisible = selectedSecondInputIndex == 0;
|
||||
SetSecondInputFileVisibility(m_isSecondInputFileNameVisible);
|
||||
}
|
||||
|
||||
void ComparisonDataWidget::SetAllDisplayValues(const AzToolsFramework::AssetFileInfoListComparison::ComparisonData& comparisonData)
|
||||
{
|
||||
using namespace AzToolsFramework;
|
||||
|
||||
// Name (Token value)
|
||||
m_ui->nameLineEdit->setText(RemoveTokenCharFromString(comparisonData.m_output));
|
||||
|
||||
// Comparison Type
|
||||
InitComparisonTypeComboBox(comparisonData);
|
||||
|
||||
// Inputs
|
||||
UpdateListOfTokenNames();
|
||||
m_ui->firstInputLineEdit->setText(QString(comparisonData.m_cachedFirstInputPath.c_str()));
|
||||
m_ui->secondInputLineEdit->setText(QString(comparisonData.m_cachedSecondInputPath.c_str()));
|
||||
|
||||
// Update fields that are not always visible
|
||||
UpdateOnComparisonTypeChanged(comparisonData.m_filePatternType != AssetFileInfoListComparison::FilePatternType::Default);
|
||||
}
|
||||
|
||||
void ComparisonDataWidget::OnNameLineEditChanged()
|
||||
{
|
||||
if (!IsComparisonDataIndexValid())
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
AZStd::string tokenName = m_ui->nameLineEdit->text().toUtf8().data();
|
||||
AzToolsFramework::AssetFileInfoListComparison::FormatOutputToken(tokenName);
|
||||
m_comparisonList->SetOutput(m_comparisonDataIndex, tokenName);
|
||||
emit comparisonDataChanged();
|
||||
emit comparisonDataTokenNameChanged(m_comparisonDataIndex);
|
||||
}
|
||||
|
||||
void ComparisonDataWidget::UpdateOnComparisonTypeChanged(bool isFilePatternOperation)
|
||||
{
|
||||
using namespace AzToolsFramework;
|
||||
|
||||
if (!IsComparisonDataIndexValid())
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
AssetFileInfoListComparison::ComparisonData comparisonData = m_comparisonList->GetComparisonList()[m_comparisonDataIndex];
|
||||
m_ui->inputBLabel->setVisible(!isFilePatternOperation);
|
||||
m_ui->secondInputComboBox->setVisible(!isFilePatternOperation);
|
||||
SetSecondInputFileVisibility(!isFilePatternOperation && m_isSecondInputFileNameVisible);
|
||||
|
||||
m_ui->filePatternLabel->setVisible(isFilePatternOperation);
|
||||
m_ui->filePatternLineEdit->setVisible(isFilePatternOperation);
|
||||
m_ui->filePatternLineEdit->setText(comparisonData.m_filePattern.c_str());
|
||||
}
|
||||
|
||||
void ComparisonDataWidget::InitComparisonTypeComboBox(const AzToolsFramework::AssetFileInfoListComparison::ComparisonData& comparisonData)
|
||||
{
|
||||
using namespace AzToolsFramework;
|
||||
|
||||
m_ui->comparisonTypeComboBox->insertItems(0, ComparisonTypeStringList);
|
||||
int initialSelectionIndex = ComparisonTypeIndex::Default;
|
||||
|
||||
if (comparisonData.m_filePatternType != AssetFileInfoListComparison::FilePatternType::Default
|
||||
&& comparisonData.m_comparisonType == AssetFileInfoListComparison::ComparisonType::FilePattern)
|
||||
{
|
||||
if (comparisonData.m_filePatternType == AssetFileInfoListComparison::FilePatternType::Wildcard)
|
||||
{
|
||||
initialSelectionIndex = ComparisonTypeIndex::Wildcard;
|
||||
}
|
||||
else
|
||||
{
|
||||
initialSelectionIndex = ComparisonTypeIndex::Regex;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
switch (comparisonData.m_comparisonType)
|
||||
{
|
||||
case AssetFileInfoListComparison::ComparisonType::Default:
|
||||
break;
|
||||
case AssetFileInfoListComparison::ComparisonType::Delta:
|
||||
initialSelectionIndex = ComparisonTypeIndex::Delta;
|
||||
break;
|
||||
case AssetFileInfoListComparison::ComparisonType::Union:
|
||||
initialSelectionIndex = ComparisonTypeIndex::Union;
|
||||
break;
|
||||
case AssetFileInfoListComparison::ComparisonType::Intersection:
|
||||
initialSelectionIndex = ComparisonTypeIndex::Intersection;
|
||||
break;
|
||||
case AssetFileInfoListComparison::ComparisonType::Complement:
|
||||
initialSelectionIndex = ComparisonTypeIndex::Complement;
|
||||
break;
|
||||
default:
|
||||
AZ_Warning("AssetBundler", false, "ComparisonType ( %u ) is not supported in the Asset Bundler", comparisonData.m_comparisonType);
|
||||
}
|
||||
}
|
||||
|
||||
m_ui->comparisonTypeComboBox->setCurrentIndex(initialSelectionIndex);
|
||||
}
|
||||
|
||||
void ComparisonDataWidget::OnComparisonTypeComboBoxChanged(int index)
|
||||
{
|
||||
using namespace AzToolsFramework;
|
||||
|
||||
if (!IsComparisonDataIndexValid())
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
bool isFilePattern = false;
|
||||
|
||||
switch (index)
|
||||
{
|
||||
case ComparisonTypeIndex::Default:
|
||||
m_comparisonList->SetComparisonType(m_comparisonDataIndex, AssetFileInfoListComparison::ComparisonType::Default);
|
||||
break;
|
||||
case ComparisonTypeIndex::Delta:
|
||||
m_comparisonList->SetComparisonType(m_comparisonDataIndex, AssetFileInfoListComparison::ComparisonType::Delta);
|
||||
break;
|
||||
case ComparisonTypeIndex::Union:
|
||||
m_comparisonList->SetComparisonType(m_comparisonDataIndex, AssetFileInfoListComparison::ComparisonType::Union);
|
||||
break;
|
||||
case ComparisonTypeIndex::Intersection:
|
||||
m_comparisonList->SetComparisonType(m_comparisonDataIndex, AssetFileInfoListComparison::ComparisonType::Intersection);
|
||||
break;
|
||||
case ComparisonTypeIndex::Complement:
|
||||
m_comparisonList->SetComparisonType(m_comparisonDataIndex, AssetFileInfoListComparison::ComparisonType::Complement);
|
||||
break;
|
||||
case ComparisonTypeIndex::Wildcard:
|
||||
m_comparisonList->SetComparisonType(m_comparisonDataIndex, AssetFileInfoListComparison::ComparisonType::FilePattern);
|
||||
m_comparisonList->SetFilePatternType(m_comparisonDataIndex, AssetFileInfoListComparison::FilePatternType::Wildcard);
|
||||
isFilePattern = true;
|
||||
break;
|
||||
case ComparisonTypeIndex::Regex:
|
||||
m_comparisonList->SetComparisonType(m_comparisonDataIndex, AssetFileInfoListComparison::ComparisonType::FilePattern);
|
||||
m_comparisonList->SetFilePatternType(m_comparisonDataIndex, AssetFileInfoListComparison::FilePatternType::Regex);
|
||||
isFilePattern = true;
|
||||
break;
|
||||
}
|
||||
|
||||
UpdateOnComparisonTypeChanged(isFilePattern);
|
||||
emit comparisonDataChanged();
|
||||
}
|
||||
|
||||
void ComparisonDataWidget::OnFilePatternLineEditChanged()
|
||||
{
|
||||
if (!IsComparisonDataIndexValid())
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
m_comparisonList->SetFilePattern(m_comparisonDataIndex, m_ui->filePatternLineEdit->text().toUtf8().data());
|
||||
emit comparisonDataChanged();
|
||||
}
|
||||
|
||||
void ComparisonDataWidget::OnFirstInputComboBoxChanged(int index)
|
||||
{
|
||||
AZStd::string firstInputValue;
|
||||
|
||||
if (!IsComparisonDataIndexValid())
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
m_isFirstInputFileNameVisible = index == 0;
|
||||
|
||||
if (!m_isFirstInputFileNameVisible)
|
||||
{
|
||||
// The 0th index is the default value, which translates to an empty token string.
|
||||
firstInputValue = m_ui->firstInputComboBox->currentText().toUtf8().data();
|
||||
AzToolsFramework::AssetFileInfoListComparison::FormatOutputToken(firstInputValue);
|
||||
}
|
||||
|
||||
SetFirstInputFileVisibility(m_isFirstInputFileNameVisible);
|
||||
|
||||
m_comparisonList->SetFirstInput(m_comparisonDataIndex, firstInputValue);
|
||||
emit comparisonDataChanged();
|
||||
}
|
||||
|
||||
void ComparisonDataWidget::SetFirstInputFileVisibility(bool isVisible)
|
||||
{
|
||||
m_ui->firstInputLineEdit->setVisible(isVisible);
|
||||
m_ui->firstInputBrowseButton->setVisible(isVisible);
|
||||
}
|
||||
|
||||
void ComparisonDataWidget::OnFirstInputBrowseButtonPressed()
|
||||
{
|
||||
if (!IsComparisonDataIndexValid())
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
QString absoluteFilePath = BrowseButtonPressed();
|
||||
if (absoluteFilePath.isEmpty())
|
||||
{
|
||||
// User canceled out of the dialog
|
||||
return;
|
||||
}
|
||||
|
||||
m_ui->firstInputLineEdit->setText(absoluteFilePath);
|
||||
m_comparisonList->SetCachedFirstInputPath(m_comparisonDataIndex, absoluteFilePath.toUtf8().data());
|
||||
}
|
||||
|
||||
void ComparisonDataWidget::OnSecondInputComboBoxChanged(int index)
|
||||
{
|
||||
if (!IsComparisonDataIndexValid())
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
AZStd::string secondInputValue;
|
||||
|
||||
m_isSecondInputFileNameVisible = index == 0;
|
||||
|
||||
if (!m_isSecondInputFileNameVisible)
|
||||
{
|
||||
// The 0th index is the default value, which translates to an empty token string.
|
||||
secondInputValue = m_ui->secondInputComboBox->currentText().toUtf8().data();
|
||||
AzToolsFramework::AssetFileInfoListComparison::FormatOutputToken(secondInputValue);
|
||||
}
|
||||
|
||||
SetSecondInputFileVisibility(m_isSecondInputFileNameVisible);
|
||||
|
||||
m_comparisonList->SetSecondInput(m_comparisonDataIndex, secondInputValue);
|
||||
emit comparisonDataChanged();
|
||||
}
|
||||
|
||||
void ComparisonDataWidget::SetSecondInputFileVisibility(bool isVisible)
|
||||
{
|
||||
m_ui->secondInputLineEdit->setVisible(isVisible);
|
||||
m_ui->secondInputBrowseButton->setVisible(isVisible);
|
||||
}
|
||||
|
||||
void ComparisonDataWidget::OnSecondInputBrowseButtonPressed()
|
||||
{
|
||||
if (!IsComparisonDataIndexValid())
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
QString absoluteFilePath = BrowseButtonPressed();
|
||||
if (absoluteFilePath.isEmpty())
|
||||
{
|
||||
// User canceled out of the dialog
|
||||
return;
|
||||
}
|
||||
|
||||
m_ui->secondInputLineEdit->setText(absoluteFilePath);
|
||||
m_comparisonList->SetCachedSecondInputPath(m_comparisonDataIndex, absoluteFilePath.toUtf8().data());
|
||||
}
|
||||
|
||||
QString ComparisonDataWidget::BrowseButtonPressed()
|
||||
{
|
||||
AZStd::string selectedPath = NewFileDialog::OSNewFileDialog(
|
||||
this,
|
||||
AzToolsFramework::AssetSeedManager::GetAssetListFileExtension(),
|
||||
"Asset List",
|
||||
m_defaultAssetListFileDirectory);
|
||||
AzToolsFramework::RemovePlatformIdentifier(selectedPath);
|
||||
return selectedPath.c_str();
|
||||
}
|
||||
|
||||
bool ComparisonDataWidget::IsComparisonDataIndexValid()
|
||||
{
|
||||
return m_comparisonList->GetComparisonList().size() > m_comparisonDataIndex;
|
||||
}
|
||||
|
||||
QString ComparisonDataWidget::RemoveTokenCharFromString(const AZStd::string& tokenName)
|
||||
{
|
||||
QString displayName = tokenName.c_str();
|
||||
if (displayName.startsWith(AzToolsFramework::AssetFileInfoListComparison::GetTokenIdentifier()))
|
||||
{
|
||||
displayName.remove(0, 1);
|
||||
}
|
||||
|
||||
return displayName;
|
||||
}
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
// MouseWheelEventFilter
|
||||
//////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
bool MouseWheelEventFilter::eventFilter(QObject* obj, QEvent* ev)
|
||||
{
|
||||
if (ev->type() == QEvent::Wheel)
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
return QObject::eventFilter(obj, ev);
|
||||
}
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
// ComparisonDataCard
|
||||
//////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
ComparisonDataCard::ComparisonDataCard(
|
||||
AZStd::shared_ptr<AzToolsFramework::AssetFileInfoListComparison> comparisonList,
|
||||
size_t comparisonDataIndex,
|
||||
const AZStd::string& defaultAssetListFileDirectory,
|
||||
QWidget* parent)
|
||||
: AzQtComponents::Card(parent)
|
||||
{
|
||||
m_comparisonDataWidget = new ComparisonDataWidget(comparisonList, comparisonDataIndex, defaultAssetListFileDirectory, this);
|
||||
setContentWidget(m_comparisonDataWidget);
|
||||
|
||||
connect(this, &AzQtComponents::Card::contextMenuRequested, this, &ComparisonDataCard::OnContextMenuRequested);
|
||||
}
|
||||
|
||||
void ComparisonDataCard::OnContextMenuRequested(const QPoint& position)
|
||||
{
|
||||
emit comparisonDataCardContextMenuRequested(m_comparisonDataWidget->GetComparisonDataIndex(), position);
|
||||
}
|
||||
|
||||
} // namespace AssetBundler
|
||||
|
||||
#include <source/ui/moc_ComparisonDataWidget.cpp>
|
||||
@@ -0,0 +1,151 @@
|
||||
/*
|
||||
* 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.
|
||||
*
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#if !defined(Q_MOC_RUN)
|
||||
#include <AzCore/std/smart_ptr/shared_ptr.h>
|
||||
#include <AzCore/std/smart_ptr/make_shared.h>
|
||||
#include <AzQtComponents/Components/Widgets/Card.h>
|
||||
#include <AzToolsFramework/Asset/AssetBundler.h>
|
||||
|
||||
#include <QWidget>
|
||||
#endif
|
||||
|
||||
namespace Ui
|
||||
{
|
||||
class ComparisonDataWidget;
|
||||
}
|
||||
|
||||
namespace AssetBundler
|
||||
{
|
||||
//! Widget for displaying and editing a single Comparison Step inside a Comparison Rules file.
|
||||
class ComparisonDataWidget
|
||||
: public QWidget
|
||||
{
|
||||
Q_OBJECT
|
||||
|
||||
public:
|
||||
explicit ComparisonDataWidget(
|
||||
AZStd::shared_ptr<AzToolsFramework::AssetFileInfoListComparison> comparisonList,
|
||||
size_t comparisonDataIndex,
|
||||
const AZStd::string& defaultAssetListFileDirectory,
|
||||
QWidget* parent = nullptr);
|
||||
virtual ~ComparisonDataWidget() {}
|
||||
|
||||
enum ComparisonTypeIndex : int
|
||||
{
|
||||
Default = 0,
|
||||
Delta,
|
||||
Union,
|
||||
Intersection,
|
||||
Complement,
|
||||
Wildcard,
|
||||
Regex,
|
||||
MAX
|
||||
};
|
||||
|
||||
size_t GetComparisonDataIndex() { return m_comparisonDataIndex; }
|
||||
|
||||
void UpdateListOfTokenNames();
|
||||
|
||||
Q_SIGNALS:
|
||||
void comparisonDataChanged();
|
||||
|
||||
void comparisonDataTokenNameChanged(size_t comparisonDataIndex);
|
||||
|
||||
private:
|
||||
void SetAllDisplayValues(const AzToolsFramework::AssetFileInfoListComparison::ComparisonData& comparisonData);
|
||||
|
||||
void OnNameLineEditChanged();
|
||||
|
||||
void UpdateOnComparisonTypeChanged(bool isFilePatternOperation);
|
||||
|
||||
void InitComparisonTypeComboBox(const AzToolsFramework::AssetFileInfoListComparison::ComparisonData& comparisonData);
|
||||
|
||||
void OnComparisonTypeComboBoxChanged(int index);
|
||||
|
||||
void OnFilePatternLineEditChanged();
|
||||
|
||||
void OnFirstInputComboBoxChanged(int index);
|
||||
|
||||
void SetFirstInputFileVisibility(bool isVisible);
|
||||
|
||||
void OnFirstInputBrowseButtonPressed();
|
||||
|
||||
void OnSecondInputComboBoxChanged(int index);
|
||||
|
||||
void SetSecondInputFileVisibility(bool isVisible);
|
||||
|
||||
void OnSecondInputBrowseButtonPressed();
|
||||
|
||||
QString BrowseButtonPressed();
|
||||
|
||||
bool IsComparisonDataIndexValid();
|
||||
|
||||
QString RemoveTokenCharFromString(const AZStd::string& tokenName);
|
||||
|
||||
QSharedPointer<Ui::ComparisonDataWidget> m_ui;
|
||||
|
||||
AZStd::shared_ptr<AzToolsFramework::AssetFileInfoListComparison> m_comparisonList;
|
||||
size_t m_comparisonDataIndex;
|
||||
|
||||
AZStd::string m_defaultAssetListFileDirectory;
|
||||
|
||||
QStringList m_inputTokenNameList;
|
||||
QString m_outputAssetListFileAbsolutePath;
|
||||
|
||||
bool m_isFirstInputFileNameVisible = false;
|
||||
bool m_isSecondInputFileNameVisible = false;
|
||||
};
|
||||
|
||||
class MouseWheelEventFilter
|
||||
: public QObject
|
||||
{
|
||||
Q_OBJECT
|
||||
|
||||
public:
|
||||
explicit MouseWheelEventFilter(QObject* parent) : QObject(parent) {}
|
||||
|
||||
protected:
|
||||
bool eventFilter(QObject* obj, QEvent* ev) override;
|
||||
};
|
||||
|
||||
|
||||
//! Wrapper widget that controls the expansion state and signals that trigger a context menu of a ComparisonDataWidget.
|
||||
class ComparisonDataCard
|
||||
: public AzQtComponents::Card
|
||||
{
|
||||
Q_OBJECT
|
||||
|
||||
public:
|
||||
explicit ComparisonDataCard(
|
||||
AZStd::shared_ptr<AzToolsFramework::AssetFileInfoListComparison> comparisonList,
|
||||
size_t comparisonDataIndex,
|
||||
const AZStd::string& defaultAssetListFileDirectory,
|
||||
QWidget* parent = nullptr);
|
||||
virtual ~ComparisonDataCard() {}
|
||||
|
||||
ComparisonDataWidget* GetComparisonDataWidget() { return m_comparisonDataWidget; }
|
||||
|
||||
Q_SIGNALS:
|
||||
void comparisonDataCardContextMenuRequested(size_t comparisonDataIndex, const QPoint& position);
|
||||
|
||||
private:
|
||||
ComparisonDataWidget* m_comparisonDataWidget = nullptr;
|
||||
|
||||
private slots:
|
||||
void OnContextMenuRequested(const QPoint& position);
|
||||
};
|
||||
|
||||
|
||||
} // namespace AssetBundler
|
||||
@@ -0,0 +1,150 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<ui version="4.0">
|
||||
<class>ComparisonDataWidget</class>
|
||||
<widget class="QWidget" name="ComparisonDataWidget">
|
||||
<property name="geometry">
|
||||
<rect>
|
||||
<x>0</x>
|
||||
<y>0</y>
|
||||
<width>400</width>
|
||||
<height>300</height>
|
||||
</rect>
|
||||
</property>
|
||||
<property name="sizePolicy">
|
||||
<sizepolicy hsizetype="Preferred" vsizetype="Preferred">
|
||||
<horstretch>0</horstretch>
|
||||
<verstretch>0</verstretch>
|
||||
</sizepolicy>
|
||||
</property>
|
||||
<property name="windowTitle">
|
||||
<string>Form</string>
|
||||
</property>
|
||||
<layout class="QVBoxLayout" name="verticalLayout">
|
||||
<property name="leftMargin">
|
||||
<number>0</number>
|
||||
</property>
|
||||
<property name="topMargin">
|
||||
<number>0</number>
|
||||
</property>
|
||||
<property name="rightMargin">
|
||||
<number>0</number>
|
||||
</property>
|
||||
<property name="bottomMargin">
|
||||
<number>0</number>
|
||||
</property>
|
||||
<item>
|
||||
<widget class="QFrame" name="comparisonDataFrame">
|
||||
<layout class="QFormLayout" name="formLayout">
|
||||
<property name="sizeConstraint">
|
||||
<enum>QLayout::SetDefaultConstraint</enum>
|
||||
</property>
|
||||
<property name="labelAlignment">
|
||||
<set>Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter</set>
|
||||
</property>
|
||||
<property name="verticalSpacing">
|
||||
<number>6</number>
|
||||
</property>
|
||||
<property name="leftMargin">
|
||||
<number>0</number>
|
||||
</property>
|
||||
<property name="topMargin">
|
||||
<number>0</number>
|
||||
</property>
|
||||
<property name="rightMargin">
|
||||
<number>0</number>
|
||||
</property>
|
||||
<property name="bottomMargin">
|
||||
<number>0</number>
|
||||
</property>
|
||||
<item row="0" column="0">
|
||||
<widget class="QLabel" name="nameLabel">
|
||||
<property name="text">
|
||||
<string>Name</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="0" column="1">
|
||||
<widget class="QLineEdit" name="nameLineEdit"/>
|
||||
</item>
|
||||
<item row="1" column="0">
|
||||
<widget class="QLabel" name="comparisonTypeLabel">
|
||||
<property name="text">
|
||||
<string>Comparison Type</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="1" column="1">
|
||||
<widget class="QComboBox" name="comparisonTypeComboBox"/>
|
||||
</item>
|
||||
<item row="2" column="0">
|
||||
<widget class="QLabel" name="inputALabel">
|
||||
<property name="text">
|
||||
<string>Input A</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="2" column="1">
|
||||
<widget class="QComboBox" name="firstInputComboBox"/>
|
||||
</item>
|
||||
<item row="3" column="1">
|
||||
<layout class="QHBoxLayout" name="horizontalLayout_2">
|
||||
<property name="spacing">
|
||||
<number>10</number>
|
||||
</property>
|
||||
<item>
|
||||
<widget class="QLineEdit" name="firstInputLineEdit"/>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QPushButton" name="firstInputBrowseButton">
|
||||
<property name="text">
|
||||
<string>Browse...</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
</layout>
|
||||
</item>
|
||||
<item row="4" column="0">
|
||||
<widget class="QLabel" name="inputBLabel">
|
||||
<property name="text">
|
||||
<string>Input B</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="4" column="1">
|
||||
<widget class="QComboBox" name="secondInputComboBox"/>
|
||||
</item>
|
||||
<item row="5" column="1">
|
||||
<layout class="QHBoxLayout" name="horizontalLayout_3">
|
||||
<property name="spacing">
|
||||
<number>10</number>
|
||||
</property>
|
||||
<item>
|
||||
<widget class="QLineEdit" name="secondInputLineEdit"/>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QPushButton" name="secondInputBrowseButton">
|
||||
<property name="text">
|
||||
<string>Browse...</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
</layout>
|
||||
</item>
|
||||
<item row="6" column="0">
|
||||
<widget class="QLabel" name="filePatternLabel">
|
||||
<property name="text">
|
||||
<string>File Pattern</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="6" column="1">
|
||||
<widget class="QLineEdit" name="filePatternLineEdit"/>
|
||||
</item>
|
||||
</layout>
|
||||
</widget>
|
||||
</item>
|
||||
</layout>
|
||||
</widget>
|
||||
<resources/>
|
||||
<connections/>
|
||||
</ui>
|
||||
@@ -0,0 +1,62 @@
|
||||
/*
|
||||
* 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 <source/ui/EditSeedDialog.h>
|
||||
#include <source/ui/ui_EditSeedDialog.h>
|
||||
|
||||
#include <source/ui/PlatformSelectionWidget.h>
|
||||
|
||||
#include <QPushButton>
|
||||
|
||||
namespace AssetBundler
|
||||
{
|
||||
|
||||
EditSeedDialog::EditSeedDialog(
|
||||
QWidget* parent,
|
||||
const AzFramework::PlatformFlags& enabledPlatforms,
|
||||
const AzFramework::PlatformFlags& selectedPlatforms,
|
||||
const AzFramework::PlatformFlags& partiallySelectedPlatforms)
|
||||
: QDialog(parent)
|
||||
{
|
||||
m_ui.reset(new Ui::EditSeedDialog);
|
||||
m_ui->setupUi(this);
|
||||
|
||||
m_ui->platformSelectionWidget->Init(enabledPlatforms);
|
||||
m_ui->platformSelectionWidget->SetSelectedPlatforms(selectedPlatforms, partiallySelectedPlatforms);
|
||||
connect(m_ui->platformSelectionWidget, &PlatformSelectionWidget::PlatformsSelected, this, &EditSeedDialog::OnPlatformSelectionChanged);
|
||||
|
||||
// Set up confirm and cancel buttons
|
||||
connect(m_ui->applyChangesButton, &QPushButton::clicked, this, &QDialog::accept);
|
||||
connect(m_ui->cancelButton, &QPushButton::clicked, this, &QDialog::reject);
|
||||
}
|
||||
|
||||
AzFramework::PlatformFlags EditSeedDialog::GetPlatformFlags()
|
||||
{
|
||||
return m_ui->platformSelectionWidget->GetSelectedPlatforms();
|
||||
}
|
||||
|
||||
AzFramework::PlatformFlags EditSeedDialog::GetPartiallySelectedPlatformFlags()
|
||||
{
|
||||
return m_ui->platformSelectionWidget->GetPartiallySelectedPlatforms();
|
||||
}
|
||||
|
||||
void EditSeedDialog::OnPlatformSelectionChanged(const AzFramework::PlatformFlags& selectedPlatforms, const AzFramework::PlatformFlags& partiallySelectedPlatforms)
|
||||
{
|
||||
// Disable the "Apply Changes" button if no platforms are selected
|
||||
bool areAnyPlatformsSelected = selectedPlatforms != AzFramework::PlatformFlags::Platform_NONE ||
|
||||
partiallySelectedPlatforms != AzFramework::PlatformFlags::Platform_NONE;
|
||||
m_ui->applyChangesButton->setEnabled(areAnyPlatformsSelected);
|
||||
}
|
||||
|
||||
} // namespace AssetBundler
|
||||
|
||||
#include <source/ui/moc_EditSeedDialog.cpp>
|
||||
@@ -0,0 +1,52 @@
|
||||
/*
|
||||
* 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.
|
||||
*
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#if !defined(Q_MOC_RUN)
|
||||
#include <AzFramework/Platform/PlatformDefaults.h>
|
||||
#include <AzToolsFramework/Asset/AssetSeedManager.h>
|
||||
|
||||
#include <QDialog>
|
||||
#include <QSharedPointer>
|
||||
#endif
|
||||
|
||||
namespace Ui
|
||||
{
|
||||
class EditSeedDialog;
|
||||
}
|
||||
|
||||
namespace AssetBundler
|
||||
{
|
||||
class EditSeedDialog
|
||||
: public QDialog
|
||||
{
|
||||
Q_OBJECT
|
||||
|
||||
public:
|
||||
explicit EditSeedDialog(
|
||||
QWidget* parent,
|
||||
const AzFramework::PlatformFlags& enabledPlatforms,
|
||||
const AzFramework::PlatformFlags& selectedPlatforms,
|
||||
const AzFramework::PlatformFlags& partiallySelectedPlatforms = AzFramework::PlatformFlags::Platform_NONE);
|
||||
virtual ~EditSeedDialog() {}
|
||||
|
||||
AzFramework::PlatformFlags GetPlatformFlags();
|
||||
AzFramework::PlatformFlags GetPartiallySelectedPlatformFlags();
|
||||
|
||||
private:
|
||||
void OnPlatformSelectionChanged(const AzFramework::PlatformFlags& selectedPlatforms, const AzFramework::PlatformFlags& partiallySelectedPlatforms);
|
||||
|
||||
QSharedPointer<Ui::EditSeedDialog> m_ui;
|
||||
};
|
||||
|
||||
} // namespace AssetBundler
|
||||
@@ -0,0 +1,117 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<ui version="4.0">
|
||||
<class>EditSeedDialog</class>
|
||||
<widget class="QDialog" name="EditSeedDialog">
|
||||
<property name="geometry">
|
||||
<rect>
|
||||
<x>0</x>
|
||||
<y>0</y>
|
||||
<width>400</width>
|
||||
<height>92</height>
|
||||
</rect>
|
||||
</property>
|
||||
<property name="minimumSize">
|
||||
<size>
|
||||
<width>300</width>
|
||||
<height>0</height>
|
||||
</size>
|
||||
</property>
|
||||
<property name="windowTitle">
|
||||
<string>Edit Selected Platforms</string>
|
||||
</property>
|
||||
<property name="modal">
|
||||
<bool>true</bool>
|
||||
</property>
|
||||
<layout class="QVBoxLayout" name="verticalLayout_4">
|
||||
<property name="leftMargin">
|
||||
<number>0</number>
|
||||
</property>
|
||||
<property name="topMargin">
|
||||
<number>0</number>
|
||||
</property>
|
||||
<property name="rightMargin">
|
||||
<number>0</number>
|
||||
</property>
|
||||
<property name="bottomMargin">
|
||||
<number>0</number>
|
||||
</property>
|
||||
<item>
|
||||
<widget class="QFrame" name="inputValuesFrame">
|
||||
<property name="frameShape">
|
||||
<enum>QFrame::StyledPanel</enum>
|
||||
</property>
|
||||
<property name="frameShadow">
|
||||
<enum>QFrame::Raised</enum>
|
||||
</property>
|
||||
<layout class="QVBoxLayout" name="verticalLayout">
|
||||
<property name="leftMargin">
|
||||
<number>0</number>
|
||||
</property>
|
||||
<property name="topMargin">
|
||||
<number>0</number>
|
||||
</property>
|
||||
<property name="rightMargin">
|
||||
<number>0</number>
|
||||
</property>
|
||||
<property name="bottomMargin">
|
||||
<number>0</number>
|
||||
</property>
|
||||
<item>
|
||||
<widget class="AssetBundler::PlatformSelectionWidget" name="platformSelectionWidget" native="true"/>
|
||||
</item>
|
||||
</layout>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<layout class="QHBoxLayout" name="horizontalLayout">
|
||||
<property name="rightMargin">
|
||||
<number>10</number>
|
||||
</property>
|
||||
<property name="bottomMargin">
|
||||
<number>10</number>
|
||||
</property>
|
||||
<item>
|
||||
<spacer name="horizontalSpacer">
|
||||
<property name="orientation">
|
||||
<enum>Qt::Horizontal</enum>
|
||||
</property>
|
||||
<property name="sizeHint" stdset="0">
|
||||
<size>
|
||||
<width>40</width>
|
||||
<height>20</height>
|
||||
</size>
|
||||
</property>
|
||||
</spacer>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QPushButton" name="cancelButton">
|
||||
<property name="text">
|
||||
<string>Cancel</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QPushButton" name="applyChangesButton">
|
||||
<property name="text">
|
||||
<string>Apply Changes</string>
|
||||
</property>
|
||||
<property name="default">
|
||||
<bool>true</bool>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
</layout>
|
||||
</item>
|
||||
</layout>
|
||||
</widget>
|
||||
<customwidgets>
|
||||
<customwidget>
|
||||
<class>AssetBundler::PlatformSelectionWidget</class>
|
||||
<extends>QWidget</extends>
|
||||
<header location="global">source/ui/PlatformSelectionWidget.h</header>
|
||||
<container>1</container>
|
||||
</customwidget>
|
||||
</customwidgets>
|
||||
<resources/>
|
||||
<connections/>
|
||||
</ui>
|
||||
@@ -0,0 +1,276 @@
|
||||
/*
|
||||
* 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 <source/ui/GenerateBundlesModal.h>
|
||||
#include <source/ui/ui_GenerateBundlesModal.h>
|
||||
|
||||
#include <source/ui/AssetListTabWidget.h>
|
||||
#include <source/ui/NewFileDialog.h>
|
||||
#include <source/utils/utils.h>
|
||||
|
||||
#include <AzCore/IO/FileIO.h>
|
||||
#include <AzFramework/StringFunc/StringFunc.h>
|
||||
#include <AzToolsFramework/AssetBundle/AssetBundleAPI.h>
|
||||
|
||||
#include <QMessageBox>
|
||||
|
||||
const char CustomBundleSettingsText[] = "Custom";
|
||||
|
||||
namespace AssetBundler
|
||||
{
|
||||
GenerateBundlesModal::GenerateBundlesModal(
|
||||
QWidget* parent,
|
||||
const AZStd::string& assetListFileAbsolutePath,
|
||||
const AZStd::string& defaultBundleDirectory,
|
||||
const AZStd::string& defaultBundleSettingsDirectory,
|
||||
AssetListTabWidget* assetListTabWidget)
|
||||
: QDialog(parent)
|
||||
, m_assetListFileAbsolutePath(assetListFileAbsolutePath)
|
||||
, m_defaultBundleDirectory(defaultBundleDirectory)
|
||||
, m_defaultBundleSettingsDirectory(defaultBundleSettingsDirectory)
|
||||
, m_assetListTabWidget(assetListTabWidget)
|
||||
{
|
||||
m_ui.reset(new Ui::GenerateBundlesModal);
|
||||
m_ui->setupUi(this);
|
||||
|
||||
m_platformName = AzToolsFramework::GetPlatformIdentifier(m_assetListFileAbsolutePath);
|
||||
|
||||
// Selected Asset List
|
||||
m_ui->selectedAssetListPathLabel->setText(QString(m_assetListFileAbsolutePath.c_str()));
|
||||
|
||||
// Platform
|
||||
m_ui->platformNameLabel->setText(QString(m_platformName.c_str()));
|
||||
|
||||
// Bundle Output
|
||||
m_ui->outputBundlePathLineEdit->setReadOnly(true);
|
||||
connect(m_ui->outputBundlePathBrowseButton, &QPushButton::clicked, this, &GenerateBundlesModal::OnOutputBundleLocationBrowseButtonPressed);
|
||||
|
||||
// Bundle Settings files
|
||||
m_ui->bundleSettingsFileLineEdit->setReadOnly(true);
|
||||
m_ui->bundleSettingsFileLineEdit->setText(tr(CustomBundleSettingsText));
|
||||
connect(m_ui->bundleSettingsFileBrowseButton, &QPushButton::clicked, this, &GenerateBundlesModal::OnBundleSettingsBrowseButtonPressed);
|
||||
connect(m_ui->bundleSettingsFileSaveButton, &QPushButton::clicked, this, &GenerateBundlesModal::OnBundleSettingsSaveButtonPressed);
|
||||
|
||||
// Max Bundle Size
|
||||
m_ui->maxBundleSizeSpinBox->setRange(1, AzToolsFramework::MaxBundleSizeInMB);
|
||||
m_ui->maxBundleSizeSpinBox->setValue(AzToolsFramework::MaxBundleSizeInMB);
|
||||
m_ui->maxBundleSizeSpinBox->setButtonSymbols(QAbstractSpinBox::ButtonSymbols::NoButtons);
|
||||
m_ui->maxBundleSizeSpinBox->setSuffix(" MB");
|
||||
connect(m_ui->maxBundleSizeSpinBox, QOverload<int>::of(&QSpinBox::valueChanged), this, &GenerateBundlesModal::OnMaxBundleSizeChanged);
|
||||
|
||||
// Bundle Version
|
||||
m_ui->bundleVersionSpinBox->setRange(1, AzFramework::AssetBundleManifest::CurrentBundleVersion);
|
||||
m_ui->bundleVersionSpinBox->setValue(AzFramework::AssetBundleManifest::CurrentBundleVersion);
|
||||
m_ui->bundleVersionSpinBox->setButtonSymbols(QAbstractSpinBox::ButtonSymbols::NoButtons);
|
||||
connect(m_ui->bundleVersionSpinBox, QOverload<int>::of(&QSpinBox::valueChanged), this, &GenerateBundlesModal::OnBundleVersionChanged);
|
||||
|
||||
// Cancel and Generate Bundles buttons
|
||||
m_ui->generateBundlesButton->setEnabled(false);
|
||||
connect(m_ui->cancelButton, &QPushButton::clicked, this, &QDialog::reject);
|
||||
connect(m_ui->generateBundlesButton, &QPushButton::clicked, this, &GenerateBundlesModal::OnGenerateBundlesButtonPressed);
|
||||
|
||||
// In-memory Bundle Settings
|
||||
m_bundleSettings.m_assetFileInfoListPath = m_assetListFileAbsolutePath;
|
||||
m_bundleSettings.m_platform = m_platformName;
|
||||
m_bundleSettings.m_maxBundleSizeInMB = static_cast<AZ::u64>(m_ui->maxBundleSizeSpinBox->value());
|
||||
m_bundleSettings.m_bundleVersion = m_ui->bundleVersionSpinBox->value();
|
||||
}
|
||||
|
||||
GenerateBundlesModal::~GenerateBundlesModal()
|
||||
{
|
||||
m_assetListTabWidget = nullptr;
|
||||
}
|
||||
|
||||
void GenerateBundlesModal::OnOutputBundleLocationBrowseButtonPressed()
|
||||
{
|
||||
AZStd::string outputBundleAbsolutePath = NewFileDialog::OSNewFileDialog(
|
||||
this,
|
||||
AzToolsFramework::AssetBundleSettings::GetBundleFileExtension(),
|
||||
"Bundle",
|
||||
m_defaultBundleDirectory);
|
||||
|
||||
if (outputBundleAbsolutePath.empty())
|
||||
{
|
||||
// User canceled out of the dialog
|
||||
return;
|
||||
}
|
||||
|
||||
AzToolsFramework::RemovePlatformIdentifier(outputBundleAbsolutePath);
|
||||
AddPlatformIdentifier(outputBundleAbsolutePath, m_platformName);
|
||||
|
||||
m_bundleSettings.m_bundleFilePath = outputBundleAbsolutePath;
|
||||
|
||||
m_ui->outputBundlePathLineEdit->setText(outputBundleAbsolutePath.c_str());
|
||||
m_ui->generateBundlesButton->setEnabled(true);
|
||||
}
|
||||
|
||||
void GenerateBundlesModal::OnBundleSettingsBrowseButtonPressed()
|
||||
{
|
||||
AZStd::string bundleSettingsAbsolutePath = NewFileDialog::OSNewFileDialog(
|
||||
this,
|
||||
AzToolsFramework::AssetBundleSettings::GetBundleSettingsFileExtension(),
|
||||
"Bundle Settings",
|
||||
m_defaultBundleSettingsDirectory);
|
||||
|
||||
if (bundleSettingsAbsolutePath.empty())
|
||||
{
|
||||
// User canceled out of the dialog
|
||||
return;
|
||||
}
|
||||
|
||||
// Read in the values from the Bundle Settings file
|
||||
bool loadResult = LoadBundleSettingsValues(bundleSettingsAbsolutePath);
|
||||
if (!loadResult)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
// Update the display name for our settings
|
||||
UpdateBundleSettingsDisplayName(bundleSettingsAbsolutePath);
|
||||
}
|
||||
|
||||
bool GenerateBundlesModal::LoadBundleSettingsValues(const AZStd::string& absoluteBundleSettingsFilePath)
|
||||
{
|
||||
using namespace AzToolsFramework;
|
||||
|
||||
auto outcome = AssetBundleSettings::Load(absoluteBundleSettingsFilePath);
|
||||
if (!outcome.IsSuccess())
|
||||
{
|
||||
AZ_Error("AssetBundler", false, outcome.GetError().c_str());
|
||||
return false;
|
||||
}
|
||||
|
||||
// We don't want to overwrite all of the in-memory bundle settings, so we will just update a few
|
||||
AssetBundleSettings loadedSettings = outcome.TakeValue();
|
||||
|
||||
m_bundleSettings.m_maxBundleSizeInMB = loadedSettings.m_maxBundleSizeInMB;
|
||||
m_ui->maxBundleSizeSpinBox->setValue(static_cast<int>(m_bundleSettings.m_maxBundleSizeInMB));
|
||||
|
||||
m_bundleSettings.m_bundleVersion = loadedSettings.m_bundleVersion;
|
||||
m_ui->bundleVersionSpinBox->setValue(m_bundleSettings.m_bundleVersion);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
void GenerateBundlesModal::UpdateBundleSettingsDisplayName(const AZStd::string& absoluteBundleSettingsFilePath)
|
||||
{
|
||||
if (absoluteBundleSettingsFilePath.empty())
|
||||
{
|
||||
m_ui->bundleSettingsFileLineEdit->setText(tr(CustomBundleSettingsText));
|
||||
return;
|
||||
}
|
||||
|
||||
AZStd::string bundleSettingsFileName = absoluteBundleSettingsFilePath;
|
||||
AzToolsFramework::RemovePlatformIdentifier(bundleSettingsFileName);
|
||||
AzFramework::StringFunc::Path::GetFileName(bundleSettingsFileName.c_str(), bundleSettingsFileName);
|
||||
m_ui->bundleSettingsFileLineEdit->setText(bundleSettingsFileName.c_str());
|
||||
}
|
||||
|
||||
void GenerateBundlesModal::OnBundleSettingsSaveButtonPressed()
|
||||
{
|
||||
using namespace AzToolsFramework;
|
||||
|
||||
// Ask the user where they want to save the Bundle Settings file
|
||||
AZStd::string bundleSettingsAbsolutePath = NewFileDialog::OSNewFileDialog(
|
||||
this,
|
||||
AssetBundleSettings::GetBundleSettingsFileExtension(),
|
||||
"Bundle Settings",
|
||||
m_defaultBundleSettingsDirectory);
|
||||
|
||||
if (bundleSettingsAbsolutePath.empty())
|
||||
{
|
||||
// User canceled out of the operation
|
||||
return;
|
||||
}
|
||||
|
||||
AzToolsFramework::RemovePlatformIdentifier(bundleSettingsAbsolutePath);
|
||||
AddPlatformIdentifier(bundleSettingsAbsolutePath, m_platformName);
|
||||
|
||||
if (AZ::IO::FileIOBase::GetInstance()->Exists(bundleSettingsAbsolutePath.c_str()))
|
||||
{
|
||||
QString messageBoxText = QString(tr("Bundle Settings ( %1 ) already exists on-disk. Saving the current settings will override the existing settings. \n\nDo you wish to continue?")).arg(bundleSettingsAbsolutePath.c_str());
|
||||
|
||||
QMessageBox::StandardButton confirmDeleteFileResult = QMessageBox::question(this, QString(tr("Replace Existing Settings")), messageBoxText);
|
||||
if (confirmDeleteFileResult != QMessageBox::StandardButton::Yes)
|
||||
{
|
||||
// User canceled out of the operation
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
bool saveResult = AssetBundleSettings::Save(m_bundleSettings, bundleSettingsAbsolutePath);
|
||||
if (!saveResult)
|
||||
{
|
||||
// Error has already been thrown
|
||||
return;
|
||||
}
|
||||
|
||||
m_assetListTabWidget->AddScanPathToAssetBundlerSettings(AssetBundlingFileType::BundleSettingsFileType, bundleSettingsAbsolutePath);
|
||||
|
||||
UpdateBundleSettingsDisplayName(bundleSettingsAbsolutePath);
|
||||
}
|
||||
|
||||
void GenerateBundlesModal::OnMaxBundleSizeChanged()
|
||||
{
|
||||
m_bundleSettings.m_maxBundleSizeInMB = static_cast<AZ::u64>(m_ui->maxBundleSizeSpinBox->value());
|
||||
UpdateBundleSettingsDisplayName("");
|
||||
}
|
||||
|
||||
void GenerateBundlesModal::OnBundleVersionChanged()
|
||||
{
|
||||
m_bundleSettings.m_bundleVersion = m_ui->bundleVersionSpinBox->value();
|
||||
UpdateBundleSettingsDisplayName("");
|
||||
}
|
||||
|
||||
void GenerateBundlesModal::OnGenerateBundlesButtonPressed()
|
||||
{
|
||||
using namespace AzToolsFramework;
|
||||
|
||||
if (AZ::IO::FileIOBase::GetInstance()->Exists(m_bundleSettings.m_bundleFilePath.c_str()))
|
||||
{
|
||||
QString messageBoxText = QString(tr("Asset Bundle ( %1 ) already exists on-disk. Generating a new Bundle will override the existing Bundle. \n\nDo you wish to permanently delete the existing Bundle?")).arg(m_bundleSettings.m_bundleFilePath.c_str());
|
||||
|
||||
QMessageBox::StandardButton confirmDeleteFileResult = QMessageBox::question(this, QString(tr("Replace Existing Bundle")), messageBoxText);
|
||||
if (confirmDeleteFileResult != QMessageBox::StandardButton::Yes)
|
||||
{
|
||||
// User canceled out of the operation
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
bool result = false;
|
||||
AssetBundleCommandsBus::BroadcastResult(result, &AssetBundleCommandsBus::Events::CreateAssetBundle, m_bundleSettings);
|
||||
|
||||
// This operation will take long enough that the OS will throw up its own wait cursor,
|
||||
// but there is a slight delay where the UI is unresponsive but the cursor hasn't changed.
|
||||
// We are changing the cursor manually to avoid that.
|
||||
setCursor(Qt::WaitCursor);
|
||||
|
||||
emit QDialog::accept();
|
||||
|
||||
if (result)
|
||||
{
|
||||
m_assetListTabWidget->AddScanPathToAssetBundlerSettings(AssetBundlingFileType::BundleFileType, m_bundleSettings.m_bundleFilePath);
|
||||
|
||||
// The watched files list was updated after the files were created, so we need to force-reload them
|
||||
m_assetListTabWidget->GetGUIApplicationManager()->UpdateFiles(AssetBundlingFileType::BundleFileType, { m_bundleSettings.m_bundleFilePath });
|
||||
}
|
||||
|
||||
AZStd::vector<AZStd::string> generatedFilePaths = { m_bundleSettings.m_bundleFilePath };
|
||||
NewFileDialog::FileGenerationResultMessageBox(this, generatedFilePaths, !result);
|
||||
|
||||
unsetCursor();
|
||||
}
|
||||
|
||||
} // namespace AssetBundler
|
||||
|
||||
#include <source/ui/moc_GenerateBundlesModal.cpp>
|
||||
@@ -0,0 +1,75 @@
|
||||
/*
|
||||
* 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.
|
||||
*
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#if !defined(Q_MOC_RUN)
|
||||
#include <AzCore/std/string/string.h>
|
||||
#include <AzToolsFramework/Asset/AssetBundler.h>
|
||||
|
||||
#include <QDialog>
|
||||
#include <QSharedPointer>
|
||||
#endif
|
||||
|
||||
namespace Ui
|
||||
{
|
||||
class GenerateBundlesModal;
|
||||
}
|
||||
|
||||
namespace AssetBundler
|
||||
{
|
||||
class AssetListTabWidget;
|
||||
|
||||
class GenerateBundlesModal
|
||||
: public QDialog
|
||||
{
|
||||
Q_OBJECT
|
||||
|
||||
public:
|
||||
explicit GenerateBundlesModal(
|
||||
QWidget* parent,
|
||||
const AZStd::string& assetListFileAbsolutePath,
|
||||
const AZStd::string& defaultBundleDirectory,
|
||||
const AZStd::string& defaultBundleSettingsDirectory,
|
||||
AssetListTabWidget* assetListTabWidget);
|
||||
virtual ~GenerateBundlesModal();
|
||||
|
||||
private:
|
||||
void OnOutputBundleLocationBrowseButtonPressed();
|
||||
|
||||
void OnBundleSettingsBrowseButtonPressed();
|
||||
|
||||
bool LoadBundleSettingsValues(const AZStd::string& absoluteBundleSettingsFilePath);
|
||||
|
||||
void UpdateBundleSettingsDisplayName(const AZStd::string& absoluteBundleSettingsFilePath);
|
||||
|
||||
void OnBundleSettingsSaveButtonPressed();
|
||||
|
||||
void OnMaxBundleSizeChanged();
|
||||
|
||||
void OnBundleVersionChanged();
|
||||
|
||||
void OnGenerateBundlesButtonPressed();
|
||||
|
||||
QSharedPointer<Ui::GenerateBundlesModal> m_ui;
|
||||
|
||||
AssetListTabWidget* m_assetListTabWidget = nullptr;
|
||||
|
||||
AZStd::string m_assetListFileAbsolutePath;
|
||||
AZStd::string m_defaultBundleDirectory;
|
||||
AZStd::string m_defaultBundleSettingsDirectory;
|
||||
AZStd::string m_platformName;
|
||||
|
||||
AzToolsFramework::AssetBundleSettings m_bundleSettings;
|
||||
};
|
||||
|
||||
} // namespace AssetBundler
|
||||
@@ -0,0 +1,292 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<ui version="4.0">
|
||||
<class>GenerateBundlesModal</class>
|
||||
<widget class="QDialog" name="GenerateBundlesModal">
|
||||
<property name="windowModality">
|
||||
<enum>Qt::ApplicationModal</enum>
|
||||
</property>
|
||||
<property name="geometry">
|
||||
<rect>
|
||||
<x>0</x>
|
||||
<y>0</y>
|
||||
<width>800</width>
|
||||
<height>300</height>
|
||||
</rect>
|
||||
</property>
|
||||
<property name="sizePolicy">
|
||||
<sizepolicy hsizetype="MinimumExpanding" vsizetype="MinimumExpanding">
|
||||
<horstretch>0</horstretch>
|
||||
<verstretch>0</verstretch>
|
||||
</sizepolicy>
|
||||
</property>
|
||||
<property name="minimumSize">
|
||||
<size>
|
||||
<width>750</width>
|
||||
<height>0</height>
|
||||
</size>
|
||||
</property>
|
||||
<property name="windowTitle">
|
||||
<string>Generate Bundles</string>
|
||||
</property>
|
||||
<layout class="QVBoxLayout" name="verticalLayout">
|
||||
<property name="leftMargin">
|
||||
<number>10</number>
|
||||
</property>
|
||||
<property name="topMargin">
|
||||
<number>10</number>
|
||||
</property>
|
||||
<property name="rightMargin">
|
||||
<number>10</number>
|
||||
</property>
|
||||
<property name="bottomMargin">
|
||||
<number>10</number>
|
||||
</property>
|
||||
<item>
|
||||
<widget class="QFrame" name="bundleSettingsFrame">
|
||||
<property name="frameShape">
|
||||
<enum>QFrame::StyledPanel</enum>
|
||||
</property>
|
||||
<property name="frameShadow">
|
||||
<enum>QFrame::Raised</enum>
|
||||
</property>
|
||||
<layout class="QVBoxLayout" name="bundleSettingsFrameLayout">
|
||||
<property name="leftMargin">
|
||||
<number>5</number>
|
||||
</property>
|
||||
<property name="topMargin">
|
||||
<number>0</number>
|
||||
</property>
|
||||
<property name="rightMargin">
|
||||
<number>5</number>
|
||||
</property>
|
||||
<property name="bottomMargin">
|
||||
<number>0</number>
|
||||
</property>
|
||||
<item>
|
||||
<widget class="QFrame" name="outputBundleLocationFrame">
|
||||
<property name="frameShape">
|
||||
<enum>QFrame::StyledPanel</enum>
|
||||
</property>
|
||||
<property name="frameShadow">
|
||||
<enum>QFrame::Raised</enum>
|
||||
</property>
|
||||
<layout class="QFormLayout" name="formLayout_3">
|
||||
<property name="leftMargin">
|
||||
<number>0</number>
|
||||
</property>
|
||||
<property name="topMargin">
|
||||
<number>0</number>
|
||||
</property>
|
||||
<property name="rightMargin">
|
||||
<number>0</number>
|
||||
</property>
|
||||
<property name="bottomMargin">
|
||||
<number>0</number>
|
||||
</property>
|
||||
<item row="0" column="0">
|
||||
<widget class="QLabel" name="selectedAssetListLabel">
|
||||
<property name="text">
|
||||
<string>Asset List</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="0" column="1">
|
||||
<widget class="QLabel" name="selectedAssetListPathLabel">
|
||||
<property name="text">
|
||||
<string>TextLabel</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="1" column="0">
|
||||
<widget class="QLabel" name="platformLabel">
|
||||
<property name="text">
|
||||
<string>Platform</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="1" column="1">
|
||||
<widget class="QLabel" name="platformNameLabel">
|
||||
<property name="text">
|
||||
<string>TextLabel</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="2" column="0">
|
||||
<widget class="QLabel" name="outputBundleNameLabel">
|
||||
<property name="text">
|
||||
<string>Output Bundle Name</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="2" column="1">
|
||||
<layout class="QHBoxLayout" name="horizontalLayout_2">
|
||||
<item>
|
||||
<widget class="QLineEdit" name="outputBundlePathLineEdit"/>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QPushButton" name="outputBundlePathBrowseButton">
|
||||
<property name="text">
|
||||
<string>Browse...</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
</layout>
|
||||
</item>
|
||||
</layout>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="Line" name="line">
|
||||
<property name="orientation">
|
||||
<enum>Qt::Horizontal</enum>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QFrame" name="bundleSettingsFileFrame">
|
||||
<property name="frameShape">
|
||||
<enum>QFrame::StyledPanel</enum>
|
||||
</property>
|
||||
<property name="frameShadow">
|
||||
<enum>QFrame::Raised</enum>
|
||||
</property>
|
||||
<layout class="QFormLayout" name="formLayout">
|
||||
<property name="leftMargin">
|
||||
<number>0</number>
|
||||
</property>
|
||||
<property name="topMargin">
|
||||
<number>0</number>
|
||||
</property>
|
||||
<property name="rightMargin">
|
||||
<number>0</number>
|
||||
</property>
|
||||
<property name="bottomMargin">
|
||||
<number>0</number>
|
||||
</property>
|
||||
<item row="0" column="0">
|
||||
<widget class="QLabel" name="label_3">
|
||||
<property name="text">
|
||||
<string>Settings</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="0" column="1">
|
||||
<layout class="QHBoxLayout" name="horizontalLayout_5">
|
||||
<item>
|
||||
<widget class="QLineEdit" name="bundleSettingsFileLineEdit"/>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QPushButton" name="bundleSettingsFileBrowseButton">
|
||||
<property name="text">
|
||||
<string>Browse...</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QPushButton" name="bundleSettingsFileSaveButton">
|
||||
<property name="text">
|
||||
<string>Save</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
</layout>
|
||||
</item>
|
||||
<item row="1" column="0">
|
||||
<widget class="QLabel" name="label">
|
||||
<property name="text">
|
||||
<string>Max Bundle Size</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="1" column="1">
|
||||
<layout class="QHBoxLayout" name="horizontalLayout_3">
|
||||
<item>
|
||||
<widget class="QSpinBox" name="maxBundleSizeSpinBox"/>
|
||||
</item>
|
||||
<item>
|
||||
<spacer name="horizontalSpacer_2">
|
||||
<property name="orientation">
|
||||
<enum>Qt::Horizontal</enum>
|
||||
</property>
|
||||
<property name="sizeHint" stdset="0">
|
||||
<size>
|
||||
<width>40</width>
|
||||
<height>20</height>
|
||||
</size>
|
||||
</property>
|
||||
</spacer>
|
||||
</item>
|
||||
</layout>
|
||||
</item>
|
||||
<item row="2" column="0">
|
||||
<widget class="QLabel" name="label_2">
|
||||
<property name="text">
|
||||
<string>Bundle Version</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="2" column="1">
|
||||
<layout class="QHBoxLayout" name="horizontalLayout_4">
|
||||
<item>
|
||||
<widget class="QSpinBox" name="bundleVersionSpinBox"/>
|
||||
</item>
|
||||
<item>
|
||||
<spacer name="horizontalSpacer_3">
|
||||
<property name="orientation">
|
||||
<enum>Qt::Horizontal</enum>
|
||||
</property>
|
||||
<property name="sizeHint" stdset="0">
|
||||
<size>
|
||||
<width>40</width>
|
||||
<height>20</height>
|
||||
</size>
|
||||
</property>
|
||||
</spacer>
|
||||
</item>
|
||||
</layout>
|
||||
</item>
|
||||
</layout>
|
||||
</widget>
|
||||
</item>
|
||||
</layout>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<layout class="QHBoxLayout" name="horizontalLayout">
|
||||
<item>
|
||||
<spacer name="horizontalSpacer">
|
||||
<property name="orientation">
|
||||
<enum>Qt::Horizontal</enum>
|
||||
</property>
|
||||
<property name="sizeHint" stdset="0">
|
||||
<size>
|
||||
<width>40</width>
|
||||
<height>20</height>
|
||||
</size>
|
||||
</property>
|
||||
</spacer>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QPushButton" name="cancelButton">
|
||||
<property name="text">
|
||||
<string>Cancel</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QPushButton" name="generateBundlesButton">
|
||||
<property name="text">
|
||||
<string>Generate Bundles</string>
|
||||
</property>
|
||||
<property name="default">
|
||||
<bool>true</bool>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
</layout>
|
||||
</item>
|
||||
</layout>
|
||||
</widget>
|
||||
<resources/>
|
||||
<connections/>
|
||||
</ui>
|
||||
@@ -0,0 +1,249 @@
|
||||
/*
|
||||
* 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 <source/ui/MainWindow.h>
|
||||
#include <source/ui/ui_MainWindow.h>
|
||||
#include <source/utils/GUIApplicationManager.h>
|
||||
|
||||
#include <AzCore/std/utils.h>
|
||||
#include <AzToolsFramework/UI/Logging/LogTableItemDelegate.h>
|
||||
#include <AzQtComponents/Utilities/QtWindowUtilities.h>
|
||||
|
||||
#include <QAction>
|
||||
#include <QApplication>
|
||||
#include <QClipboard>
|
||||
#include <QCloseEvent>
|
||||
#include <QDateTime>
|
||||
#include <QDesktopServices>
|
||||
|
||||
namespace AssetBundler
|
||||
{
|
||||
|
||||
MainWindow::MainWindow(AssetBundler::GUIApplicationManager* guiApplicationManager, QWidget* parent)
|
||||
: QMainWindow(parent)
|
||||
, m_guiApplicationManager(guiApplicationManager)
|
||||
{
|
||||
m_ui.reset(new Ui::MainWindow);
|
||||
m_ui->setupUi(this);
|
||||
|
||||
m_ui->verticalLayout->setContentsMargins(0, 0, 0, 0);
|
||||
|
||||
// Set up Log
|
||||
m_logModel.reset(new AzToolsFramework::Logging::LogTableModel(this));
|
||||
m_ui->logTableView->setModel(m_logModel.data());
|
||||
m_ui->logTableView->setIndentation(0);
|
||||
|
||||
m_ui->logTableView->setContextMenuPolicy(Qt::CustomContextMenu);
|
||||
connect(m_ui->logTableView, &QWidget::customContextMenuRequested, this, &MainWindow::ShowLogContextMenu);
|
||||
|
||||
AZ::Debug::TraceMessageBus::Handler::BusConnect();
|
||||
|
||||
// Create the Unsaved Changes Popup
|
||||
m_unsavedChangesMsgBox.reset(new QMessageBox(this));
|
||||
m_unsavedChangesMsgBox->setText(tr("There are unsaved changes."));
|
||||
m_unsavedChangesMsgBox->setInformativeText(tr("Would you like to save all changes before quitting?"));
|
||||
m_unsavedChangesMsgBox->setStandardButtons(QMessageBox::Save | QMessageBox::Discard | QMessageBox::Cancel);
|
||||
m_unsavedChangesMsgBox->setDefaultButton(QMessageBox::Save);
|
||||
|
||||
// Set up Quit functionality
|
||||
m_ui->actionClose->setShortcut(Qt::Key_Q | Qt::CTRL);
|
||||
m_ui->actionClose->setMenuRole(QAction::QuitRole);
|
||||
connect(m_ui->actionClose, SIGNAL(triggered()), this, SLOT(close()));
|
||||
this->addAction(m_ui->actionClose);
|
||||
|
||||
// Set up Tabs
|
||||
AssetBundlerTabWidget::InitAssetBundlerSettings(m_guiApplicationManager->GetCurrentProjectFolder().c_str());
|
||||
|
||||
m_seedListTab.reset(new SeedTabWidget(this, m_guiApplicationManager, QString(m_guiApplicationManager->GetAssetBundlingFolder().c_str())));
|
||||
m_ui->tabWidget->addTab(m_seedListTab.data(), m_seedListTab->GetTabTitle());
|
||||
|
||||
m_assetListTab.reset(new AssetListTabWidget(this, m_guiApplicationManager));
|
||||
m_ui->tabWidget->addTab(m_assetListTab.data(), m_assetListTab->GetTabTitle());
|
||||
|
||||
m_rulesTab.reset(new RulesTabWidget(this, m_guiApplicationManager));
|
||||
m_ui->tabWidget->addTab(m_rulesTab.data(), m_rulesTab->GetTabTitle());
|
||||
|
||||
m_bundleListTab.reset(new BundleListTabWidget(this, m_guiApplicationManager));
|
||||
m_ui->tabWidget->addTab(m_bundleListTab.data(), m_bundleListTab->GetTabTitle());
|
||||
|
||||
// Set up link to documentation
|
||||
QAction* supportAction = new QAction(QIcon(":/stylesheet/img/help.svg"), "", this);
|
||||
connect(supportAction, &QAction::triggered, this, &MainWindow::OnSupportClicked);
|
||||
connect(m_ui->actionDocumentation, &QAction::triggered, this, &MainWindow::OnSupportClicked);
|
||||
m_ui->tabWidget->setActionToolBarVisible();
|
||||
m_ui->tabWidget->addAction(supportAction);
|
||||
|
||||
// Set up Save functionality
|
||||
m_ui->actionSave->setShortcut(Qt::Key_S | Qt::CTRL);
|
||||
connect(m_ui->actionSave, &QAction::triggered, this, &MainWindow::SaveCurrentSelection);
|
||||
|
||||
m_ui->actionSaveAll->setShortcut(Qt::Key_S | Qt::CTRL | Qt::SHIFT);
|
||||
connect(m_ui->actionSaveAll, &QAction::triggered, this, &MainWindow::SaveAll);
|
||||
}
|
||||
|
||||
MainWindow::~MainWindow()
|
||||
{
|
||||
AZ::Debug::TraceMessageBus::Handler::BusDisconnect();
|
||||
m_guiApplicationManager = nullptr;
|
||||
}
|
||||
|
||||
void MainWindow::Activate()
|
||||
{
|
||||
m_seedListTab->Activate();
|
||||
m_rulesTab->Activate();
|
||||
m_assetListTab->Activate();
|
||||
m_bundleListTab->Activate();
|
||||
}
|
||||
|
||||
void MainWindow::ApplyConfig()
|
||||
{
|
||||
const GUIApplicationManager::Config& config = m_guiApplicationManager->GetConfig();
|
||||
// Event Log Details
|
||||
m_ui->logTableView->header()->resizeSection(AzToolsFramework::Logging::LogTableModel::ColumnType, config.logTypeColumnWidth);
|
||||
m_ui->logTableView->header()->resizeSection(AzToolsFramework::Logging::LogTableModel::ColumnWindow, config.logSourceColumnWidth);
|
||||
|
||||
m_seedListTab->ApplyConfig();
|
||||
m_assetListTab->ApplyConfig();
|
||||
m_rulesTab->ApplyConfig();
|
||||
m_bundleListTab->ApplyConfig();
|
||||
}
|
||||
|
||||
void MainWindow::WriteToLog(const AZStd::string& message, AzToolsFramework::Logging::LogLine::LogType logType)
|
||||
{
|
||||
WriteToLog(message.c_str(), logType);
|
||||
}
|
||||
|
||||
void MainWindow::WriteToLog(const QString& message, AzToolsFramework::Logging::LogLine::LogType logType)
|
||||
{
|
||||
WriteToLog(message.toUtf8().data(), logType);
|
||||
}
|
||||
|
||||
void MainWindow::WriteToLog(const char* message, AzToolsFramework::Logging::LogLine::LogType logType)
|
||||
{
|
||||
WriteToLog(message, "AssetBundler", logType);
|
||||
}
|
||||
|
||||
void MainWindow::WriteToLog(const char* message, const char* window, AzToolsFramework::Logging::LogLine::LogType logType)
|
||||
{
|
||||
m_logModel->AppendLine(
|
||||
AzToolsFramework::Logging::LogLine(
|
||||
message,
|
||||
window,
|
||||
logType,
|
||||
QDateTime::currentMSecsSinceEpoch()));
|
||||
m_ui->logTableView->scrollToBottom();
|
||||
}
|
||||
|
||||
bool MainWindow::OnPreError(const char* window, const char* /*fileName*/, int /*line*/, const char* /*func*/, const char* message)
|
||||
{
|
||||
WriteToLog(message, window, AzToolsFramework::Logging::LogLine::LogType::TYPE_ERROR);
|
||||
return true;
|
||||
}
|
||||
|
||||
bool MainWindow::OnPreWarning(const char* window, const char* /*fileName*/, int /*line*/, const char* /*func*/, const char* message)
|
||||
{
|
||||
WriteToLog(message, window, AzToolsFramework::Logging::LogLine::LogType::TYPE_WARNING);
|
||||
return true;
|
||||
}
|
||||
|
||||
bool MainWindow::OnPrintf(const char* /*window*/, const char* /*message*/)
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
void MainWindow::ShowWindow()
|
||||
{
|
||||
AzQtComponents::bringWindowToTop(this);
|
||||
}
|
||||
|
||||
void MainWindow::closeEvent(QCloseEvent* event)
|
||||
{
|
||||
if (!HasUnsavedChanges())
|
||||
{
|
||||
// No need to ask the user if they want to quit when there are no unsaved changes
|
||||
event->accept();
|
||||
return;
|
||||
}
|
||||
|
||||
int unsavedChangesResult = m_unsavedChangesMsgBox->exec();
|
||||
|
||||
switch (unsavedChangesResult)
|
||||
{
|
||||
case QMessageBox::Save:
|
||||
// Save All was clicked
|
||||
SaveAll();
|
||||
event->accept();
|
||||
break;
|
||||
case QMessageBox::Discard:
|
||||
// Don't Save was clicked
|
||||
event->accept();
|
||||
break;
|
||||
case QMessageBox::Cancel:
|
||||
// Cancel was clicked
|
||||
event->ignore();
|
||||
break;
|
||||
default:
|
||||
// should never be reached
|
||||
AZ_Assert(false, "No result was returned by the Unsaved Changes Message Box!");
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
void MainWindow::OnSupportClicked()
|
||||
{
|
||||
QDesktopServices::openUrl(
|
||||
QStringLiteral("https://docs.aws.amazon.com/lumberyard/latest/userguide/asset-bundler-overview.html"));
|
||||
}
|
||||
|
||||
void MainWindow::ShowLogContextMenu(const QPoint& pos)
|
||||
{
|
||||
QModelIndex index = m_ui->logTableView->indexAt(pos);
|
||||
|
||||
QMenu menu;
|
||||
|
||||
QAction* action = menu.addAction(tr("Copy line"), this, [&]()
|
||||
{
|
||||
QApplication::clipboard()->setText(index.data(AzToolsFramework::Logging::LogTableModel::LogLineTextRole).toString());
|
||||
});
|
||||
action->setEnabled(index.isValid());
|
||||
|
||||
menu.exec(m_ui->logTableView->mapToGlobal(pos));
|
||||
}
|
||||
|
||||
bool MainWindow::HasUnsavedChanges()
|
||||
{
|
||||
return m_seedListTab->HasUnsavedChanges() || m_rulesTab->HasUnsavedChanges();
|
||||
}
|
||||
|
||||
void MainWindow::SaveCurrentSelection()
|
||||
{
|
||||
switch (m_ui->tabWidget->currentIndex())
|
||||
{
|
||||
case TabIndex::Seeds:
|
||||
m_seedListTab->SaveCurrentSelection();
|
||||
break;
|
||||
case TabIndex::Rules:
|
||||
m_rulesTab->SaveCurrentSelection();
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
void MainWindow::SaveAll()
|
||||
{
|
||||
m_seedListTab->SaveAll();
|
||||
m_rulesTab->SaveAll();
|
||||
}
|
||||
} // namespace AssetBundler
|
||||
|
||||
#include <source/ui/moc_MainWindow.cpp>
|
||||
@@ -0,0 +1,105 @@
|
||||
/*
|
||||
* 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.
|
||||
*
|
||||
*/
|
||||
#pragma once
|
||||
|
||||
#if !defined(Q_MOC_RUN)
|
||||
#include <source/ui/AssetListTabWidget.h>
|
||||
#include <source/ui/SeedTabWidget.h>
|
||||
#include <source/ui/BundleListTabWidget.h>
|
||||
#include <source/ui/RulesTabWidget.h>
|
||||
|
||||
#include <AzCore/Debug/TraceMessageBus.h>
|
||||
#include <AzToolsFramework/UI/Logging/LogLine.h>
|
||||
#include <AzToolsFramework/UI/Logging/LogTableModel.h>
|
||||
|
||||
#include <QMainWindow>
|
||||
#include <QMessageBox>
|
||||
#include <QSharedPointer>
|
||||
#endif
|
||||
|
||||
namespace Ui
|
||||
{
|
||||
class MainWindow;
|
||||
}
|
||||
|
||||
namespace AssetBundler
|
||||
{
|
||||
class GUIApplicationManager;
|
||||
|
||||
class MainWindow
|
||||
: public QMainWindow
|
||||
, public AZ::Debug::TraceMessageBus::Handler
|
||||
{
|
||||
Q_OBJECT
|
||||
|
||||
public:
|
||||
|
||||
explicit MainWindow(AssetBundler::GUIApplicationManager* guiApplicationManager, QWidget* parent = 0);
|
||||
virtual ~MainWindow();
|
||||
|
||||
void Activate();
|
||||
|
||||
void ApplyConfig();
|
||||
|
||||
void WriteToLog(const AZStd::string& message, AzToolsFramework::Logging::LogLine::LogType logType);
|
||||
void WriteToLog(const QString& message, AzToolsFramework::Logging::LogLine::LogType logType);
|
||||
void WriteToLog(const char* message, AzToolsFramework::Logging::LogLine::LogType logType);
|
||||
void WriteToLog(const char* message, const char* window, AzToolsFramework::Logging::LogLine::LogType logType);
|
||||
|
||||
/////////////////////////////////////////////////////////
|
||||
// TraceMessageBus overrides
|
||||
bool OnPreError(const char* window, const char* fileName, int line, const char* func, const char* message) override;
|
||||
bool OnPreWarning(const char* window, const char* fileName, int line, const char* func, const char* message) override;
|
||||
bool OnPrintf(const char* window, const char* message) override;
|
||||
/////////////////////////////////////////////////////////
|
||||
|
||||
public Q_SLOTS:
|
||||
void ShowWindow();
|
||||
|
||||
protected:
|
||||
void closeEvent(QCloseEvent* event) override;
|
||||
|
||||
private:
|
||||
QSharedPointer<Ui::MainWindow> m_ui;
|
||||
|
||||
// Tabs
|
||||
QSharedPointer<AssetListTabWidget> m_assetListTab;
|
||||
QSharedPointer<SeedTabWidget> m_seedListTab;
|
||||
QSharedPointer<RulesTabWidget> m_rulesTab;
|
||||
QSharedPointer<BundleListTabWidget> m_bundleListTab;
|
||||
|
||||
enum TabIndex
|
||||
{
|
||||
Seeds,
|
||||
AssetLists,
|
||||
Rules,
|
||||
Bundles,
|
||||
MAX
|
||||
};
|
||||
|
||||
void OnSupportClicked();
|
||||
|
||||
// Log
|
||||
QSharedPointer<AzToolsFramework::Logging::LogTableModel> m_logModel;
|
||||
|
||||
void ShowLogContextMenu(const QPoint& pos);
|
||||
|
||||
// Detecting Unsaved Changes
|
||||
QSharedPointer<QMessageBox> m_unsavedChangesMsgBox;
|
||||
|
||||
bool HasUnsavedChanges();
|
||||
void SaveCurrentSelection();
|
||||
void SaveAll();
|
||||
|
||||
AssetBundler::GUIApplicationManager* m_guiApplicationManager = nullptr;
|
||||
};
|
||||
} // namespace AssetBundler
|
||||
@@ -0,0 +1,112 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<ui version="4.0">
|
||||
<class>MainWindow</class>
|
||||
<widget class="QMainWindow" name="MainWindow">
|
||||
<property name="geometry">
|
||||
<rect>
|
||||
<x>0</x>
|
||||
<y>0</y>
|
||||
<width>1200</width>
|
||||
<height>1000</height>
|
||||
</rect>
|
||||
</property>
|
||||
<property name="minimumSize">
|
||||
<size>
|
||||
<width>200</width>
|
||||
<height>200</height>
|
||||
</size>
|
||||
</property>
|
||||
<property name="windowTitle">
|
||||
<string>Asset Bundler</string>
|
||||
</property>
|
||||
<widget class="QWidget" name="centralwidget">
|
||||
<layout class="QVBoxLayout" name="verticalLayout">
|
||||
<item>
|
||||
<widget class="AzQtComponents::TabWidget" name="tabWidget">
|
||||
<property name="currentIndex">
|
||||
<number>-1</number>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="AzQtComponents::TableView" name="logTableView">
|
||||
<property name="sizePolicy">
|
||||
<sizepolicy hsizetype="Expanding" vsizetype="Minimum">
|
||||
<horstretch>0</horstretch>
|
||||
<verstretch>0</verstretch>
|
||||
</sizepolicy>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
</layout>
|
||||
</widget>
|
||||
<widget class="QMenuBar" name="menubar">
|
||||
<property name="geometry">
|
||||
<rect>
|
||||
<x>0</x>
|
||||
<y>0</y>
|
||||
<width>1200</width>
|
||||
<height>21</height>
|
||||
</rect>
|
||||
</property>
|
||||
<widget class="QMenu" name="menuFile">
|
||||
<property name="title">
|
||||
<string>File</string>
|
||||
</property>
|
||||
<addaction name="actionSave"/>
|
||||
<addaction name="actionSaveAll"/>
|
||||
<addaction name="separator"/>
|
||||
<addaction name="actionClose"/>
|
||||
</widget>
|
||||
<widget class="QMenu" name="menuHelp">
|
||||
<property name="title">
|
||||
<string>Help</string>
|
||||
</property>
|
||||
<addaction name="actionDocumentation"/>
|
||||
</widget>
|
||||
<addaction name="menuFile"/>
|
||||
<addaction name="menuHelp"/>
|
||||
</widget>
|
||||
<action name="actionSave">
|
||||
<property name="text">
|
||||
<string>Save</string>
|
||||
</property>
|
||||
</action>
|
||||
<action name="actionClose">
|
||||
<property name="text">
|
||||
<string>Close</string>
|
||||
</property>
|
||||
</action>
|
||||
<action name="actionDocumentation">
|
||||
<property name="text">
|
||||
<string>Documentation</string>
|
||||
</property>
|
||||
</action>
|
||||
<action name="actionAbout_Asset_Bundler">
|
||||
<property name="text">
|
||||
<string>About Asset Bundler</string>
|
||||
</property>
|
||||
</action>
|
||||
<action name="actionSaveAll">
|
||||
<property name="text">
|
||||
<string>Save All</string>
|
||||
</property>
|
||||
</action>
|
||||
</widget>
|
||||
<customwidgets>
|
||||
<customwidget>
|
||||
<class>AzQtComponents::TableView</class>
|
||||
<extends>QTreeView</extends>
|
||||
<header location="global">AzQtComponents/Components/Widgets/TableView.h</header>
|
||||
<container>1</container>
|
||||
</customwidget>
|
||||
<customwidget>
|
||||
<class>AzQtComponents::TabWidget</class>
|
||||
<extends>QTabWidget</extends>
|
||||
<header location="global">AzQtComponents/Components/Widgets/TabWidget.h</header>
|
||||
<container>1</container>
|
||||
</customwidget>
|
||||
</customwidgets>
|
||||
<resources/>
|
||||
<connections/>
|
||||
</ui>
|
||||
@@ -0,0 +1,224 @@
|
||||
/*
|
||||
* 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 <source/ui/NewFileDialog.h>
|
||||
#include <source/ui/ui_NewFileDialog.h>
|
||||
|
||||
#include <source/ui/PlatformSelectionWidget.h>
|
||||
#include <source/utils/utils.h>
|
||||
|
||||
#include <AzCore/IO/FileIO.h>
|
||||
#include <AzFramework/StringFunc/StringFunc.h>
|
||||
#include <AzToolsFramework/Asset/AssetBundler.h>
|
||||
|
||||
#include <QLineEdit>
|
||||
#include <QMessageBox>
|
||||
#include <QPushButton>
|
||||
|
||||
namespace AssetBundler
|
||||
{
|
||||
NewFileDialog::NewFileDialog(
|
||||
QWidget* parent,
|
||||
const QString& dialogTitle,
|
||||
const QString& startingPath,
|
||||
const char* fileExtension,
|
||||
const QString& fileNameFilter,
|
||||
const AzFramework::PlatformFlags& enabledPlatforms,
|
||||
bool isRunningRule)
|
||||
: QDialog(parent)
|
||||
, m_startingPath(startingPath)
|
||||
, m_fileExtension(fileExtension)
|
||||
{
|
||||
m_ui.reset(new Ui::NewFileDialog);
|
||||
m_ui->setupUi(this);
|
||||
|
||||
setWindowTitle(dialogTitle);
|
||||
|
||||
// Set up File Name section
|
||||
m_ui->fileNameLineEdit->setEnabled(false);
|
||||
connect(m_ui->browseButton, &QPushButton::clicked, this, &NewFileDialog::OnBrowseButtonPressed);
|
||||
|
||||
m_newFileDialog.setFileMode(QFileDialog::AnyFile);
|
||||
m_newFileDialog.setNameFilter(fileNameFilter);
|
||||
m_newFileDialog.setViewMode(QFileDialog::Detail);
|
||||
m_newFileDialog.setDirectory(m_startingPath);
|
||||
// We are not creating a new file when Qt thinks we are, so we need to block signals or else the file watcher will be triggered too soon
|
||||
m_newFileDialog.blockSignals(true);
|
||||
|
||||
// Set up Platform selection
|
||||
QString disabledPatformMessageOverride;
|
||||
if (isRunningRule)
|
||||
{
|
||||
disabledPatformMessageOverride = tr("This platform is not valid for all input Asset Lists.");
|
||||
}
|
||||
m_ui->platformSelectionWidget->Init(enabledPlatforms, disabledPatformMessageOverride);
|
||||
connect(m_ui->platformSelectionWidget, &PlatformSelectionWidget::PlatformsSelected, this, &NewFileDialog::OnPlatformSelectionChanged);
|
||||
|
||||
// Set up Cancel and Create New File buttons
|
||||
m_ui->createFileButton->setEnabled(false);
|
||||
connect(m_ui->cancelButton, &QPushButton::clicked, this, &QDialog::reject);
|
||||
connect(m_ui->createFileButton, &QPushButton::clicked, this, &NewFileDialog::OnCreateFileButtonPressed);
|
||||
}
|
||||
|
||||
AZStd::string NewFileDialog::GetAbsoluteFilePath()
|
||||
{
|
||||
return m_absoluteFilePath;
|
||||
}
|
||||
|
||||
AzFramework::PlatformFlags NewFileDialog::GetPlatformFlags()
|
||||
{
|
||||
return m_ui->platformSelectionWidget->GetSelectedPlatforms();
|
||||
}
|
||||
|
||||
void NewFileDialog::OnBrowseButtonPressed()
|
||||
{
|
||||
int result = m_newFileDialog.exec();
|
||||
if (result == QDialog::DialogCode::Accepted)
|
||||
{
|
||||
m_absoluteFilePath = m_newFileDialog.selectedFiles()[0].toUtf8().data();
|
||||
AzToolsFramework::RemovePlatformIdentifier(m_absoluteFilePath);
|
||||
|
||||
if (m_fileExtension && !AzFramework::StringFunc::Path::HasExtension(m_absoluteFilePath.c_str()))
|
||||
{
|
||||
m_absoluteFilePath.append(".");
|
||||
m_absoluteFilePath.append(m_fileExtension);
|
||||
}
|
||||
|
||||
m_ui->fileNameLineEdit->setEnabled(true);
|
||||
m_ui->fileNameLineEdit->setText(m_absoluteFilePath.c_str());
|
||||
}
|
||||
|
||||
m_fileNameIsValid = !m_absoluteFilePath.empty();
|
||||
m_ui->createFileButton->setEnabled(m_platformIsValid && m_fileNameIsValid);
|
||||
}
|
||||
|
||||
void NewFileDialog::OnPlatformSelectionChanged(const AzFramework::PlatformFlags& selectedPlatforms)
|
||||
{
|
||||
// Hide the "Create File" button if no platforms are selected
|
||||
m_platformIsValid = selectedPlatforms != AzFramework::PlatformFlags::Platform_NONE;
|
||||
m_ui->createFileButton->setEnabled(m_platformIsValid && m_fileNameIsValid);
|
||||
}
|
||||
|
||||
void NewFileDialog::OnCreateFileButtonPressed()
|
||||
{
|
||||
// Check to see if any of the selected platform-specific files already exist on-disk
|
||||
QString overwriteExistingFilesList;
|
||||
AZStd::fixed_vector<AZStd::string, AzFramework::NumPlatforms> selectedPlatformNames = AzFramework::PlatformHelper::GetPlatforms(GetPlatformFlags());
|
||||
for (const AZStd::string& platformName : selectedPlatformNames)
|
||||
{
|
||||
FilePath platformSpecificFilePath(GetAbsoluteFilePath(), platformName);
|
||||
const char* platformSpecificFileAbsolutePath = platformSpecificFilePath.AbsolutePath().c_str();
|
||||
if (AZ::IO::FileIOBase::GetInstance()->Exists(platformSpecificFileAbsolutePath))
|
||||
{
|
||||
overwriteExistingFilesList.append(QString("%1\n").arg(platformSpecificFileAbsolutePath));
|
||||
}
|
||||
}
|
||||
|
||||
// Ask the user if they are sure they want to overwrite existing files
|
||||
if (!overwriteExistingFilesList.isEmpty())
|
||||
{
|
||||
QString messageBoxText = QString(tr("The following files already exist on-disk. Generating new files will overwrite the existing ones.\n\n%1\n\nDo you wish to permanently delete the existing files?")).arg(overwriteExistingFilesList);
|
||||
|
||||
QMessageBox::StandardButton confirmDeleteFileResult = QMessageBox::question(this, QString(tr("Replace Existing Files")), messageBoxText);
|
||||
if (confirmDeleteFileResult != QMessageBox::StandardButton::Yes)
|
||||
{
|
||||
// User canceled out of the operation
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
emit QDialog::accept();
|
||||
}
|
||||
|
||||
AZStd::string NewFileDialog::OSNewFileDialog(QWidget* parent, const char* fileExtension, const char* fileTypeDisplayName, const AZStd::string& startingDirectory)
|
||||
{
|
||||
QFileDialog filePathDialog(parent);
|
||||
filePathDialog.setFileMode(QFileDialog::AnyFile);
|
||||
filePathDialog.setNameFilter(QString(tr("%1 (*.%2)")).arg(fileTypeDisplayName).arg(fileExtension));
|
||||
filePathDialog.setViewMode(QFileDialog::Detail);
|
||||
filePathDialog.setDirectory(startingDirectory.c_str());
|
||||
|
||||
// Since we handle file creation instead of the OS, we have to block signals or else the model will be reloaded,
|
||||
// and our in-memory changes will be lost.
|
||||
filePathDialog.blockSignals(true);
|
||||
int result = filePathDialog.exec();
|
||||
if (result == QDialog::DialogCode::Rejected || filePathDialog.selectedFiles().empty())
|
||||
{
|
||||
// User canceled out of the file dialog, cancel operation
|
||||
return "";
|
||||
}
|
||||
|
||||
AZStd::string absoluteFilePath(filePathDialog.selectedFiles()[0].toUtf8().data());
|
||||
if (!AzFramework::StringFunc::Path::HasExtension(absoluteFilePath.c_str()))
|
||||
{
|
||||
absoluteFilePath = AZStd::string::format("%s%c%s", absoluteFilePath.c_str(), AZ_FILESYSTEM_EXTENSION_SEPARATOR, fileExtension);
|
||||
}
|
||||
|
||||
return absoluteFilePath;
|
||||
}
|
||||
|
||||
int NewFileDialog::FileGenerationResultMessageBox(QWidget* parent, const AZStd::vector<AZStd::string>& generatedFiles, bool generatedWithErrors)
|
||||
{
|
||||
QMessageBox messageBox(parent);
|
||||
messageBox.setStandardButtons(QMessageBox::Ok);
|
||||
messageBox.setDefaultButton(QMessageBox::Ok);
|
||||
|
||||
if (generatedFiles.empty())
|
||||
{
|
||||
messageBox.setText(QString("No files were generated. Please refer to the console for more information."));
|
||||
messageBox.setIcon(QMessageBox::Critical);
|
||||
return messageBox.exec();
|
||||
}
|
||||
|
||||
QString messageText;
|
||||
if (generatedWithErrors)
|
||||
{
|
||||
messageText = QString("The following files were generated with errors. Please refer to the console for more information.\n\n");
|
||||
messageBox.setIcon(QMessageBox::Warning);
|
||||
}
|
||||
else
|
||||
{
|
||||
messageText = QString("You have successfully generated:\n\n");
|
||||
messageBox.setIcon(QMessageBox::NoIcon);
|
||||
}
|
||||
|
||||
AZStd::string fileName;
|
||||
for (const AZStd::string& filePath : generatedFiles)
|
||||
{
|
||||
AzFramework::StringFunc::Path::GetFullFileName(filePath.c_str(), fileName);
|
||||
messageText.append(QString("%1\n").arg(fileName.c_str()));
|
||||
}
|
||||
|
||||
AZStd::string extension;
|
||||
AzFramework::StringFunc::Path::GetExtension(fileName.c_str(), extension, false);
|
||||
if (extension == AzToolsFramework::AssetSeedManager::GetAssetListFileExtension())
|
||||
{
|
||||
messageText.append("\nVisit the Asset Lists tab to see the lists.");
|
||||
}
|
||||
else if (extension == AzToolsFramework::AssetBundleSettings::GetBundleFileExtension())
|
||||
{
|
||||
messageText.append("\nVisit the Completed Bundles tab to see the bundles.");
|
||||
}
|
||||
|
||||
messageBox.setText(messageText);
|
||||
|
||||
// QMessageBoxes try to shrink to the smallest size possible, so we need to make a spacer
|
||||
QSpacerItem* horizontalSpacer = new QSpacerItem(550, 0, QSizePolicy::Minimum, QSizePolicy::Expanding);
|
||||
QGridLayout* layout = static_cast<QGridLayout*>(messageBox.layout());
|
||||
layout->addItem(horizontalSpacer, layout->rowCount(), 0, 1, layout->columnCount());
|
||||
|
||||
return messageBox.exec();
|
||||
}
|
||||
|
||||
} //namespace AssetBundler
|
||||
|
||||
#include <source/ui/moc_NewFileDialog.cpp>
|
||||
@@ -0,0 +1,73 @@
|
||||
/*
|
||||
* 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.
|
||||
*
|
||||
*/
|
||||
#pragma once
|
||||
|
||||
#if !defined(Q_MOC_RUN)
|
||||
#include <AzCore/std/string/string.h>
|
||||
#include <AzFramework/Platform/PlatformDefaults.h>
|
||||
|
||||
#include <QDialog>
|
||||
#include <QFileDialog>
|
||||
#include <QSharedPointer>
|
||||
#endif
|
||||
|
||||
namespace Ui
|
||||
{
|
||||
class NewFileDialog;
|
||||
}
|
||||
|
||||
namespace AssetBundler
|
||||
{
|
||||
class GUIApplicationManager;
|
||||
|
||||
class NewFileDialog
|
||||
: public QDialog
|
||||
{
|
||||
Q_OBJECT
|
||||
|
||||
public:
|
||||
explicit NewFileDialog(
|
||||
QWidget* parent,
|
||||
const QString& dialogTitle,
|
||||
const QString& startingPath,
|
||||
const char* fileExtension,
|
||||
const QString& fileNameFilter,
|
||||
const AzFramework::PlatformFlags& enabledPlatforms,
|
||||
bool isRunningRule = false);
|
||||
virtual ~NewFileDialog() {}
|
||||
|
||||
AZStd::string GetAbsoluteFilePath();
|
||||
AzFramework::PlatformFlags GetPlatformFlags();
|
||||
|
||||
//! A standard OS-specific New File Dialog, but blocks all Qt signals from the dialog and does NOT create a new file.
|
||||
//! Use in place of the static QFileDialog functions to avoid unexpected file watcher updates.
|
||||
//! Returns the absolute path of the file the user either selected or attempted to create, or an empty string if the user canceled out of the dialog.
|
||||
static AZStd::string OSNewFileDialog(QWidget* parent, const char* fileExtension, const char* fileTypeDisplayName, const AZStd::string& startingDirectory);
|
||||
|
||||
static int FileGenerationResultMessageBox(QWidget* parent, const AZStd::vector<AZStd::string>& generatedFiles, bool generatedWithErrors);
|
||||
|
||||
private:
|
||||
void OnBrowseButtonPressed();
|
||||
void OnPlatformSelectionChanged(const AzFramework::PlatformFlags& selectedPlatforms);
|
||||
void OnCreateFileButtonPressed();
|
||||
|
||||
QSharedPointer<Ui::NewFileDialog> m_ui;
|
||||
QString m_startingPath;
|
||||
const char* m_fileExtension;
|
||||
QFileDialog m_newFileDialog;
|
||||
|
||||
AZStd::string m_absoluteFilePath;
|
||||
|
||||
bool m_fileNameIsValid = false;
|
||||
bool m_platformIsValid = false;
|
||||
};
|
||||
} // namespace AssetBundler
|
||||
@@ -0,0 +1,154 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<ui version="4.0">
|
||||
<class>NewFileDialog</class>
|
||||
<widget class="QDialog" name="NewFileDialog">
|
||||
<property name="windowModality">
|
||||
<enum>Qt::ApplicationModal</enum>
|
||||
</property>
|
||||
<property name="geometry">
|
||||
<rect>
|
||||
<x>0</x>
|
||||
<y>0</y>
|
||||
<width>450</width>
|
||||
<height>90</height>
|
||||
</rect>
|
||||
</property>
|
||||
<property name="sizePolicy">
|
||||
<sizepolicy hsizetype="MinimumExpanding" vsizetype="Expanding">
|
||||
<horstretch>0</horstretch>
|
||||
<verstretch>0</verstretch>
|
||||
</sizepolicy>
|
||||
</property>
|
||||
<property name="minimumSize">
|
||||
<size>
|
||||
<width>450</width>
|
||||
<height>0</height>
|
||||
</size>
|
||||
</property>
|
||||
<property name="windowTitle">
|
||||
<string>Dialog</string>
|
||||
</property>
|
||||
<property name="modal">
|
||||
<bool>true</bool>
|
||||
</property>
|
||||
<layout class="QVBoxLayout" name="verticalLayout_5">
|
||||
<property name="leftMargin">
|
||||
<number>0</number>
|
||||
</property>
|
||||
<property name="topMargin">
|
||||
<number>0</number>
|
||||
</property>
|
||||
<property name="rightMargin">
|
||||
<number>0</number>
|
||||
</property>
|
||||
<property name="bottomMargin">
|
||||
<number>0</number>
|
||||
</property>
|
||||
<item>
|
||||
<widget class="QFrame" name="inputValuesFrame">
|
||||
<property name="frameShape">
|
||||
<enum>QFrame::StyledPanel</enum>
|
||||
</property>
|
||||
<property name="frameShadow">
|
||||
<enum>QFrame::Raised</enum>
|
||||
</property>
|
||||
<layout class="QVBoxLayout" name="verticalLayout">
|
||||
<property name="leftMargin">
|
||||
<number>0</number>
|
||||
</property>
|
||||
<property name="topMargin">
|
||||
<number>0</number>
|
||||
</property>
|
||||
<property name="rightMargin">
|
||||
<number>0</number>
|
||||
</property>
|
||||
<property name="bottomMargin">
|
||||
<number>0</number>
|
||||
</property>
|
||||
<item>
|
||||
<layout class="QHBoxLayout" name="horizontalLayout_6">
|
||||
<item>
|
||||
<widget class="QLabel" name="fileNameLabel">
|
||||
<property name="text">
|
||||
<string>Save As:</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QLineEdit" name="fileNameLineEdit">
|
||||
<property name="readOnly">
|
||||
<bool>true</bool>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QPushButton" name="browseButton">
|
||||
<property name="text">
|
||||
<string>Browse...</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
</layout>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="AssetBundler::PlatformSelectionWidget" name="platformSelectionWidget" native="true"/>
|
||||
</item>
|
||||
</layout>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<layout class="QHBoxLayout" name="horizontalLayout">
|
||||
<property name="rightMargin">
|
||||
<number>10</number>
|
||||
</property>
|
||||
<property name="bottomMargin">
|
||||
<number>10</number>
|
||||
</property>
|
||||
<item>
|
||||
<spacer name="horizontalSpacer">
|
||||
<property name="orientation">
|
||||
<enum>Qt::Horizontal</enum>
|
||||
</property>
|
||||
<property name="sizeHint" stdset="0">
|
||||
<size>
|
||||
<width>40</width>
|
||||
<height>20</height>
|
||||
</size>
|
||||
</property>
|
||||
</spacer>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QPushButton" name="cancelButton">
|
||||
<property name="text">
|
||||
<string>Cancel</string>
|
||||
</property>
|
||||
<property name="default">
|
||||
<bool>false</bool>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QPushButton" name="createFileButton">
|
||||
<property name="text">
|
||||
<string>Create New File</string>
|
||||
</property>
|
||||
<property name="default">
|
||||
<bool>true</bool>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
</layout>
|
||||
</item>
|
||||
</layout>
|
||||
</widget>
|
||||
<customwidgets>
|
||||
<customwidget>
|
||||
<class>AssetBundler::PlatformSelectionWidget</class>
|
||||
<extends>QWidget</extends>
|
||||
<header location="global">source/ui/PlatformSelectionWidget.h</header>
|
||||
<container>1</container>
|
||||
</customwidget>
|
||||
</customwidgets>
|
||||
<resources/>
|
||||
<connections/>
|
||||
</ui>
|
||||
@@ -0,0 +1,126 @@
|
||||
/*
|
||||
* 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 <source/ui/PlatformSelectionWidget.h>
|
||||
#include <source/ui/ui_PlatformSelectionWidget.h>
|
||||
|
||||
#include <AzCore/std/string/string.h>
|
||||
|
||||
namespace AssetBundler
|
||||
{
|
||||
|
||||
PlatformSelectionWidget::PlatformSelectionWidget(QWidget* parent)
|
||||
: QWidget(parent)
|
||||
{
|
||||
m_ui.reset(new Ui::PlatformSelectionWidget);
|
||||
m_ui->setupUi(this);
|
||||
|
||||
m_platformHelper.reset(new AzFramework::PlatformHelper);
|
||||
|
||||
m_selectedPlatforms = AzFramework::PlatformFlags::Platform_NONE;
|
||||
m_partiallySelectedPlatforms = AzFramework::PlatformFlags::Platform_NONE;
|
||||
}
|
||||
|
||||
void PlatformSelectionWidget::Init(const AzFramework::PlatformFlags& enabledPlatforms, const QString& disabledPatformMessageOverride)
|
||||
{
|
||||
using namespace AzFramework;
|
||||
|
||||
// Set up Platform Checkboxes
|
||||
for (const AZStd::string_view& platformString : m_platformHelper->GetPlatforms(PlatformFlags::AllNamedPlatforms))
|
||||
{
|
||||
// Create the CheckBox and store what platform it maps to
|
||||
QSharedPointer<QCheckBox> platformCheckBox(new QCheckBox(QString::fromUtf8(platformString.data(), platformString.size())));
|
||||
m_platformCheckBoxes.push_back(platformCheckBox);
|
||||
PlatformFlags currentPlatformFlag = m_platformHelper->GetPlatformFlag(platformString);
|
||||
m_platformList.push_back(currentPlatformFlag);
|
||||
|
||||
// Add the CheckBox to the view
|
||||
m_ui->platformCheckBoxLayout->addWidget(platformCheckBox.data());
|
||||
|
||||
// If the platform is not enabled for the current project, disable it and tell the user
|
||||
if ((enabledPlatforms & currentPlatformFlag) == PlatformFlags::Platform_NONE)
|
||||
{
|
||||
platformCheckBox->setEnabled(false);
|
||||
if (disabledPatformMessageOverride.isEmpty())
|
||||
{
|
||||
platformCheckBox->setToolTip(tr("This platform is not enabled for the current project."));
|
||||
}
|
||||
else
|
||||
{
|
||||
platformCheckBox->setToolTip(disabledPatformMessageOverride);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
connect(platformCheckBox.data(), &QCheckBox::stateChanged, this, &PlatformSelectionWidget::OnPlatformSelectionChanged);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void PlatformSelectionWidget::SetSelectedPlatforms(const AzFramework::PlatformFlags& selectedPlatforms, const AzFramework::PlatformFlags& partiallySelectedPlatforms)
|
||||
{
|
||||
m_selectedPlatforms = AzFramework::PlatformFlags::Platform_NONE;
|
||||
m_partiallySelectedPlatforms = AzFramework::PlatformFlags::Platform_NONE;
|
||||
for (int checkBoxIndex = 0; checkBoxIndex < m_platformCheckBoxes.size(); ++checkBoxIndex)
|
||||
{
|
||||
AzFramework::PlatformFlags checkBoxPlatform = m_platformList[checkBoxIndex];
|
||||
bool isSelected = (checkBoxPlatform & selectedPlatforms) != AzFramework::PlatformFlags::Platform_NONE;
|
||||
m_platformCheckBoxes[checkBoxIndex]->setChecked(isSelected);
|
||||
if (isSelected)
|
||||
{
|
||||
m_selectedPlatforms |= checkBoxPlatform;
|
||||
}
|
||||
|
||||
// Set the check status to Qt::PartiallyChecked when some of the selected items support the current platform
|
||||
bool isPartiallySelected = (checkBoxPlatform & partiallySelectedPlatforms) != AzFramework::PlatformFlags::Platform_NONE;
|
||||
if (isPartiallySelected)
|
||||
{
|
||||
m_platformCheckBoxes[checkBoxIndex]->setCheckState(Qt::PartiallyChecked);
|
||||
m_partiallySelectedPlatforms |= checkBoxPlatform;
|
||||
}
|
||||
}
|
||||
|
||||
emit PlatformsSelected(m_selectedPlatforms, m_partiallySelectedPlatforms);
|
||||
}
|
||||
|
||||
AzFramework::PlatformFlags PlatformSelectionWidget::GetSelectedPlatforms()
|
||||
{
|
||||
return m_selectedPlatforms;
|
||||
}
|
||||
|
||||
AzFramework::PlatformFlags PlatformSelectionWidget::GetPartiallySelectedPlatforms()
|
||||
{
|
||||
return m_partiallySelectedPlatforms;
|
||||
}
|
||||
|
||||
void PlatformSelectionWidget::OnPlatformSelectionChanged()
|
||||
{
|
||||
m_selectedPlatforms = AzFramework::PlatformFlags::Platform_NONE;
|
||||
m_partiallySelectedPlatforms = AzFramework::PlatformFlags::Platform_NONE;
|
||||
for (int checkBoxIndex = 0; checkBoxIndex < m_platformCheckBoxes.size(); ++checkBoxIndex)
|
||||
{
|
||||
if (m_platformCheckBoxes[checkBoxIndex]->checkState() == Qt::Checked)
|
||||
{
|
||||
m_selectedPlatforms |= m_platformList[checkBoxIndex];
|
||||
}
|
||||
else if (m_platformCheckBoxes[checkBoxIndex]->checkState() == Qt::PartiallyChecked)
|
||||
{
|
||||
m_partiallySelectedPlatforms |= m_platformList[checkBoxIndex];
|
||||
}
|
||||
}
|
||||
|
||||
emit PlatformsSelected(m_selectedPlatforms, m_partiallySelectedPlatforms);
|
||||
}
|
||||
|
||||
} // namespace AssetBundler
|
||||
|
||||
#include <source/ui/moc_PlatformSelectionWidget.cpp>
|
||||
@@ -0,0 +1,62 @@
|
||||
/*
|
||||
* 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.
|
||||
*
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#if !defined(Q_MOC_RUN)
|
||||
#include <AzCore/std/smart_ptr/unique_ptr.h>
|
||||
#include <AzFramework/Platform/PlatformDefaults.h>
|
||||
|
||||
#include <QCheckBox>
|
||||
#include <QSharedPointer>
|
||||
#include <QWidget>
|
||||
#endif
|
||||
|
||||
namespace Ui
|
||||
{
|
||||
class PlatformSelectionWidget;
|
||||
}
|
||||
|
||||
namespace AssetBundler
|
||||
{
|
||||
class PlatformSelectionWidget
|
||||
: public QWidget
|
||||
{
|
||||
Q_OBJECT
|
||||
|
||||
public:
|
||||
explicit PlatformSelectionWidget(QWidget* parent);
|
||||
virtual ~PlatformSelectionWidget() {}
|
||||
|
||||
void Init(const AzFramework::PlatformFlags& enabledPlatforms, const QString& disabledPatformMessageOverride = "");
|
||||
|
||||
void SetSelectedPlatforms(const AzFramework::PlatformFlags& selectedPlatforms, const AzFramework::PlatformFlags& partiallySelectedPlatforms);
|
||||
|
||||
AzFramework::PlatformFlags GetSelectedPlatforms();
|
||||
AzFramework::PlatformFlags GetPartiallySelectedPlatforms();
|
||||
|
||||
Q_SIGNALS:
|
||||
void PlatformsSelected(AzFramework::PlatformFlags selectedPlatforms, AzFramework::PlatformFlags partiallySelectedPlatforms);
|
||||
|
||||
private:
|
||||
void OnPlatformSelectionChanged();
|
||||
|
||||
QSharedPointer<Ui::PlatformSelectionWidget> m_ui;
|
||||
AZStd::unique_ptr<AzFramework::PlatformHelper> m_platformHelper;
|
||||
|
||||
QVector<QSharedPointer<QCheckBox>> m_platformCheckBoxes;
|
||||
AZStd::vector<AzFramework::PlatformFlags> m_platformList;
|
||||
|
||||
AzFramework::PlatformFlags m_selectedPlatforms;
|
||||
AzFramework::PlatformFlags m_partiallySelectedPlatforms;
|
||||
};
|
||||
} // namespace AssetBundler
|
||||
@@ -0,0 +1,49 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<ui version="4.0">
|
||||
<class>PlatformSelectionWidget</class>
|
||||
<widget class="QWidget" name="PlatformSelectionWidget">
|
||||
<property name="geometry">
|
||||
<rect>
|
||||
<x>0</x>
|
||||
<y>0</y>
|
||||
<width>400</width>
|
||||
<height>300</height>
|
||||
</rect>
|
||||
</property>
|
||||
<property name="windowTitle">
|
||||
<string>Form</string>
|
||||
</property>
|
||||
<layout class="QFormLayout" name="formLayout">
|
||||
<property name="labelAlignment">
|
||||
<set>Qt::AlignLeading|Qt::AlignLeft|Qt::AlignTop</set>
|
||||
</property>
|
||||
<property name="leftMargin">
|
||||
<number>0</number>
|
||||
</property>
|
||||
<property name="topMargin">
|
||||
<number>0</number>
|
||||
</property>
|
||||
<property name="rightMargin">
|
||||
<number>0</number>
|
||||
</property>
|
||||
<property name="bottomMargin">
|
||||
<number>0</number>
|
||||
</property>
|
||||
<item row="0" column="0">
|
||||
<widget class="QLabel" name="platformsLabel">
|
||||
<property name="text">
|
||||
<string>Platforms:</string>
|
||||
</property>
|
||||
<property name="alignment">
|
||||
<set>Qt::AlignLeading|Qt::AlignLeft|Qt::AlignTop</set>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="0" column="1">
|
||||
<layout class="QVBoxLayout" name="platformCheckBoxLayout"/>
|
||||
</item>
|
||||
</layout>
|
||||
</widget>
|
||||
<resources/>
|
||||
<connections/>
|
||||
</ui>
|
||||
@@ -0,0 +1,432 @@
|
||||
/*
|
||||
* 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 <source/ui/RulesTabWidget.h>
|
||||
#include <source/ui/ui_RulesTabWidget.h>
|
||||
|
||||
#include <source/models/RulesFileTableModel.h>
|
||||
#include <source/ui/ComparisonDataWidget.h>
|
||||
#include <source/ui/NewFileDialog.h>
|
||||
#include <source/utils/GUIApplicationManager.h>
|
||||
#include <source/utils/utils.h>
|
||||
|
||||
#include <AzCore/Outcome/Outcome.h>
|
||||
#include <AzFramework/StringFunc/StringFunc.h>
|
||||
#include <AzToolsFramework/Asset/AssetBundler.h>
|
||||
#include <AzToolsFramework/AssetBundle/AssetBundleAPI.h>
|
||||
#include <AzQtComponents/Components/FilteredSearchWidget.h>
|
||||
|
||||
#include <QAbstractTableModel>
|
||||
#include <QItemSelectionModel>
|
||||
#include <QMenu>
|
||||
#include <QPushButton>
|
||||
|
||||
|
||||
namespace AssetBundler
|
||||
{
|
||||
RulesTabWidget::RulesTabWidget(QWidget* parent, GUIApplicationManager* guiApplicationManager)
|
||||
: AssetBundlerTabWidget(parent, guiApplicationManager)
|
||||
{
|
||||
m_ui.reset(new Ui::RulesTabWidget);
|
||||
m_ui->setupUi(this);
|
||||
|
||||
m_ui->mainVerticalLayout->setContentsMargins(MarginSize, MarginSize, MarginSize, MarginSize);
|
||||
|
||||
m_fileTableModel.reset(new RulesFileTableModel);
|
||||
m_ui->fileTableView->setModel(m_fileTableModel.data());
|
||||
|
||||
// Table View of all Rules files
|
||||
m_fileTableFilterModel.reset(new AssetBundlerFileTableFilterModel(this, m_fileTableModel->GetFileNameColumnIndex(), m_fileTableModel->GetTimeStampColumnIndex()));
|
||||
|
||||
m_fileTableFilterModel->setSourceModel(m_fileTableModel.data());
|
||||
m_ui->fileTableView->setModel(m_fileTableFilterModel.data());
|
||||
connect(m_ui->fileFilteredSearchWidget, &AzQtComponents::FilteredSearchWidget::TextFilterChanged,
|
||||
m_fileTableFilterModel.data(), static_cast<void (QSortFilterProxyModel::*)(const QString&)>(&AssetBundlerFileTableFilterModel::FilterChanged));
|
||||
|
||||
connect(m_ui->fileTableView->selectionModel(), &QItemSelectionModel::selectionChanged, this, &RulesTabWidget::FileSelectionChanged);
|
||||
|
||||
m_ui->fileTableView->setIndentation(0);
|
||||
|
||||
// New File Button
|
||||
connect(m_ui->createNewFileButton, &QPushButton::clicked, this, &RulesTabWidget::OnNewFileButtonPressed);
|
||||
|
||||
// Run Rule Button
|
||||
m_ui->runRuleButton->setEnabled(false);
|
||||
connect(m_ui->runRuleButton, &QPushButton::clicked, this, &RulesTabWidget::OnRunRuleButtonPressed);
|
||||
|
||||
// Add Comparison Step button
|
||||
connect(m_ui->addComparisonStepButton, &QPushButton::clicked, this, &RulesTabWidget::AddNewComparisonStep);
|
||||
|
||||
SetModelDataSource();
|
||||
}
|
||||
|
||||
bool RulesTabWidget::HasUnsavedChanges()
|
||||
{
|
||||
return m_fileTableModel->HasUnsavedChanges();
|
||||
}
|
||||
|
||||
void RulesTabWidget::Reload()
|
||||
{
|
||||
m_fileTableModel->Reload(AzToolsFramework::AssetFileInfoListComparison::GetComparisonRulesFileExtension(), m_watchedFolders, m_watchedFiles);
|
||||
FileSelectionChanged();
|
||||
}
|
||||
|
||||
bool RulesTabWidget::SaveCurrentSelection()
|
||||
{
|
||||
return m_fileTableModel->Save(m_selectedFileTableIndex);
|
||||
}
|
||||
|
||||
bool RulesTabWidget::SaveAll()
|
||||
{
|
||||
return m_fileTableModel->SaveAll();
|
||||
}
|
||||
|
||||
void RulesTabWidget::SetModelDataSource()
|
||||
{
|
||||
// Remove the current watched folders and files
|
||||
m_guiApplicationManager->RemoveWatchedPaths(m_watchedFolders + m_watchedFiles);
|
||||
|
||||
// Set the new watched folder for the model
|
||||
m_watchedFolders.clear();
|
||||
m_watchedFiles.clear();
|
||||
m_watchedFolders.insert(m_guiApplicationManager->GetRulesFolder().c_str());
|
||||
ReadScanPathsFromAssetBundlerSettings(AssetBundlingFileType::RulesFileType);
|
||||
|
||||
m_guiApplicationManager->AddWatchedPaths(m_watchedFolders + m_watchedFiles);
|
||||
}
|
||||
|
||||
AzQtComponents::TableView* RulesTabWidget::GetFileTableView()
|
||||
{
|
||||
return m_ui->fileTableView;
|
||||
}
|
||||
|
||||
QModelIndex RulesTabWidget::GetSelectedFileTableIndex()
|
||||
{
|
||||
return m_selectedFileTableIndex;
|
||||
}
|
||||
|
||||
AssetBundlerAbstractFileTableModel* RulesTabWidget::GetFileTableModel()
|
||||
{
|
||||
return m_fileTableModel.get();
|
||||
}
|
||||
|
||||
void RulesTabWidget::SetActiveProjectLabel(const QString& labelText)
|
||||
{
|
||||
m_ui->activeProjectLabel->setText(labelText);
|
||||
}
|
||||
|
||||
void RulesTabWidget::ApplyConfig()
|
||||
{
|
||||
const GUIApplicationManager::Config& config = m_guiApplicationManager->GetConfig();
|
||||
m_ui->fileTableFrame->setFixedWidth(config.fileTableWidth);
|
||||
m_ui->fileTableView->header()->resizeSection(RulesFileTableModel::Column::ColumnFileName, config.fileNameColumnWidth);
|
||||
}
|
||||
|
||||
|
||||
void RulesTabWidget::FileSelectionChanged(const QItemSelection& /*selected*/, const QItemSelection& /*deselected*/)
|
||||
{
|
||||
if (m_ui->fileTableView->selectionModel()->selectedRows().size() == 0)
|
||||
{
|
||||
m_selectedFileTableIndex = QModelIndex();
|
||||
m_selectedComparisonRules = nullptr;
|
||||
m_ui->runRuleButton->setEnabled(false);
|
||||
m_ui->addComparisonStepButton->setEnabled(false);
|
||||
m_ui->rulesFileAbsolutePathLabel->clear();
|
||||
RemoveAllComparisonDataCards();
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
m_ui->runRuleButton->setEnabled(true);
|
||||
m_ui->addComparisonStepButton->setEnabled(true);
|
||||
|
||||
m_selectedFileTableIndex = m_fileTableFilterModel->mapToSource(m_ui->fileTableView->selectionModel()->selectedRows()[0]);
|
||||
m_selectedComparisonRules = m_fileTableModel->GetComparisonSteps(m_selectedFileTableIndex);
|
||||
|
||||
m_ui->rulesFileAbsolutePathLabel->setText(m_fileTableModel->GetFileAbsolutePath(m_selectedFileTableIndex).c_str());
|
||||
|
||||
RebuildComparisonDataCardList();
|
||||
}
|
||||
|
||||
void RulesTabWidget::OnNewFileButtonPressed()
|
||||
{
|
||||
AZStd::string absoluteFilePath = NewFileDialog::OSNewFileDialog(
|
||||
this,
|
||||
AzToolsFramework::AssetFileInfoListComparison::GetComparisonRulesFileExtension(),
|
||||
"Comparison Rules",
|
||||
m_guiApplicationManager->GetRulesFolder());
|
||||
|
||||
if (absoluteFilePath.empty())
|
||||
{
|
||||
// User canceled out of the dialog
|
||||
return;
|
||||
}
|
||||
|
||||
AZStd::vector<AZStd::string> createdFile = m_fileTableModel->CreateNewFiles(absoluteFilePath);
|
||||
if (!createdFile.empty())
|
||||
{
|
||||
AddScanPathToAssetBundlerSettings(AssetBundlingFileType::RulesFileType, createdFile.at(0));
|
||||
}
|
||||
}
|
||||
|
||||
void RulesTabWidget::OnRunRuleButtonPressed()
|
||||
{
|
||||
using namespace AzToolsFramework;
|
||||
|
||||
// Determine which platforms all of the input Asset List files have in common
|
||||
AzFramework::PlatformFlags commonPlatforms = AzFramework::PlatformFlags::AllNamedPlatforms;
|
||||
for (const AssetFileInfoListComparison::ComparisonData& comparisonStep : m_selectedComparisonRules->GetComparisonList())
|
||||
{
|
||||
if (!comparisonStep.m_cachedFirstInputPath.empty())
|
||||
{
|
||||
commonPlatforms = commonPlatforms & GetPlatformsOnDiskForPlatformSpecificFile(comparisonStep.m_cachedFirstInputPath);
|
||||
}
|
||||
|
||||
if (!comparisonStep.m_cachedSecondInputPath.empty())
|
||||
{
|
||||
commonPlatforms = commonPlatforms & GetPlatformsOnDiskForPlatformSpecificFile(comparisonStep.m_cachedSecondInputPath);
|
||||
}
|
||||
}
|
||||
|
||||
if (commonPlatforms == AzFramework::PlatformFlags::Platform_NONE)
|
||||
{
|
||||
AZ_Error("AssetBundler", false, "Unable to run Rule: Input Asset List files have no platforms in common.");
|
||||
return;
|
||||
}
|
||||
|
||||
// Prompt the user to select an output path and the platforms to run the rule on
|
||||
NewFileDialog runRuleDialog = NewFileDialog(
|
||||
this,
|
||||
"Run Rule",
|
||||
QString(m_guiApplicationManager->GetAssetListsFolder().c_str()),
|
||||
AzToolsFramework::AssetSeedManager::GetAssetListFileExtension(),
|
||||
QString(tr("Asset List (*.%1)")).arg(AzToolsFramework::AssetSeedManager::GetAssetListFileExtension()),
|
||||
commonPlatforms,
|
||||
true);
|
||||
|
||||
auto dialogResponse = runRuleDialog.exec();
|
||||
if (dialogResponse == QDialog::DialogCode::Rejected)
|
||||
{
|
||||
// User canceled the operation
|
||||
return;
|
||||
}
|
||||
|
||||
AZStd::vector<AZStd::string> outputFilePaths;
|
||||
bool hasFileGenerationErrors = false;
|
||||
|
||||
AZStd::fixed_vector<AZStd::string, AzFramework::NumPlatforms> selectedPlatformNames = AzFramework::PlatformHelper::GetPlatforms(runRuleDialog.GetPlatformFlags());
|
||||
for (const AZStd::string& platformName : selectedPlatformNames)
|
||||
{
|
||||
// We do not want to modify the original Rules file, as we do not save Asset List file paths to disk
|
||||
AssetFileInfoListComparison currentFileCopy = *m_selectedComparisonRules.get();
|
||||
|
||||
//Update the first and second input values with any non-token Asset List file paths that have been set,
|
||||
size_t numComparisonSteps = currentFileCopy.GetNumComparisonSteps();
|
||||
for (size_t comparisonStepIndex = 0; comparisonStepIndex < numComparisonSteps; ++comparisonStepIndex)
|
||||
{
|
||||
AssetFileInfoListComparison::ComparisonData comparisonStep = currentFileCopy.GetComparisonList()[comparisonStepIndex];
|
||||
if (comparisonStep.m_firstInput.empty())
|
||||
{
|
||||
if (comparisonStep.m_cachedFirstInputPath.empty())
|
||||
{
|
||||
AZ_Error("AssetBundler", false, "Unable to run Rule: Comparison Step #%u has no specified first input.", comparisonStepIndex);
|
||||
return;
|
||||
}
|
||||
|
||||
FilePath firstInput = FilePath(comparisonStep.m_cachedFirstInputPath, platformName);
|
||||
currentFileCopy.SetFirstInput(comparisonStepIndex, firstInput.AbsolutePath());
|
||||
}
|
||||
|
||||
if (comparisonStep.m_comparisonType != AssetFileInfoListComparison::ComparisonType::FilePattern
|
||||
&& comparisonStep.m_secondInput.empty())
|
||||
{
|
||||
if (comparisonStep.m_cachedSecondInputPath.empty())
|
||||
{
|
||||
AZ_Error("AssetBundler", false, "Unable to run Rule: Comparison Step #%u has no specified second input.", comparisonStepIndex);
|
||||
return;
|
||||
}
|
||||
|
||||
FilePath secondInput = FilePath(comparisonStep.m_cachedSecondInputPath, platformName);
|
||||
currentFileCopy.SetSecondInput(comparisonStepIndex, secondInput.AbsolutePath());
|
||||
}
|
||||
}
|
||||
|
||||
// Set the output location of the Asset List file that will be generated
|
||||
FilePath finalOutputPath = FilePath(runRuleDialog.GetAbsoluteFilePath(), platformName);
|
||||
currentFileCopy.SetOutput(numComparisonSteps - 1, finalOutputPath.AbsolutePath());
|
||||
|
||||
//Run the Rule
|
||||
auto compareOutcome = currentFileCopy.CompareAndSaveResults();
|
||||
if (compareOutcome.IsSuccess())
|
||||
{
|
||||
outputFilePaths.emplace_back(finalOutputPath.AbsolutePath());
|
||||
}
|
||||
else
|
||||
{
|
||||
hasFileGenerationErrors = true;
|
||||
AZ_Error("AssetBundler", false, compareOutcome.GetError().c_str());
|
||||
}
|
||||
}
|
||||
|
||||
// Add created files to the file watcher
|
||||
for (const AZStd::string& absolutePath : outputFilePaths)
|
||||
{
|
||||
AddScanPathToAssetBundlerSettings(AssetBundlingFileType::AssetListFileType, absolutePath);
|
||||
}
|
||||
|
||||
// The watched files list was updated after the files were created, so we need to force-reload them
|
||||
m_guiApplicationManager->UpdateFiles(AssetBundlingFileType::AssetListFileType, outputFilePaths);
|
||||
|
||||
NewFileDialog::FileGenerationResultMessageBox(this, outputFilePaths, hasFileGenerationErrors);
|
||||
}
|
||||
|
||||
void RulesTabWidget::MarkFileChanged()
|
||||
{
|
||||
m_fileTableModel->MarkFileChanged(m_selectedFileTableIndex);
|
||||
}
|
||||
|
||||
void RulesTabWidget::RebuildComparisonDataCardList()
|
||||
{
|
||||
RemoveAllComparisonDataCards();
|
||||
PopulateComparisonDataCardList();
|
||||
}
|
||||
|
||||
void RulesTabWidget::PopulateComparisonDataCardList()
|
||||
{
|
||||
if (!m_selectedComparisonRules)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
for (int index = 0; index < m_selectedComparisonRules->GetComparisonList().size(); ++index)
|
||||
{
|
||||
CreateComparisonDataCard(m_selectedComparisonRules, static_cast<size_t>(index));
|
||||
}
|
||||
}
|
||||
|
||||
void RulesTabWidget::CreateComparisonDataCard(AZStd::shared_ptr<AzToolsFramework::AssetFileInfoListComparison> comparisonList, size_t comparisonDataIndex)
|
||||
{
|
||||
ComparisonDataCard* comparisonDataCard = new ComparisonDataCard(comparisonList, comparisonDataIndex, m_guiApplicationManager->GetAssetListsFolder());
|
||||
comparisonDataCard->setTitle(tr("Step %1").arg(static_cast<int>(comparisonDataIndex) + 1));
|
||||
m_ui->comparisonDataListLayout->addWidget(comparisonDataCard);
|
||||
m_comparisonDataCardList.push_back(comparisonDataCard);
|
||||
|
||||
ComparisonDataWidget* comparisonDataWidget = comparisonDataCard->GetComparisonDataWidget();
|
||||
connect(comparisonDataCard, &ComparisonDataCard::comparisonDataCardContextMenuRequested, this, &RulesTabWidget::OnComparisonDataCardContextMenuRequested);
|
||||
connect(comparisonDataWidget, &ComparisonDataWidget::comparisonDataChanged, this, &RulesTabWidget::MarkFileChanged);
|
||||
connect(comparisonDataWidget, &ComparisonDataWidget::comparisonDataTokenNameChanged, this, &RulesTabWidget::OnAnyTokenNameChanged);
|
||||
|
||||
comparisonDataCard->show();
|
||||
}
|
||||
|
||||
void RulesTabWidget::RemoveAllComparisonDataCards()
|
||||
{
|
||||
m_comparisonDataCardList.clear();
|
||||
|
||||
while (!m_ui->comparisonDataListLayout->isEmpty())
|
||||
{
|
||||
QLayoutItem* item = m_ui->comparisonDataListLayout->takeAt(0);
|
||||
item->widget()->hide();
|
||||
delete item;
|
||||
}
|
||||
}
|
||||
|
||||
void RulesTabWidget::AddNewComparisonStep()
|
||||
{
|
||||
if (!m_selectedComparisonRules)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
if (!m_selectedComparisonRules->AddComparisonStep(AzToolsFramework::AssetFileInfoListComparison::ComparisonData()))
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
CreateComparisonDataCard(m_selectedComparisonRules, m_selectedComparisonRules->GetComparisonList().size() - 1);
|
||||
MarkFileChanged();
|
||||
}
|
||||
|
||||
void RulesTabWidget::RemoveComparisonStep(size_t comparisonDataIndex)
|
||||
{
|
||||
if (!m_selectedComparisonRules)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
if (m_selectedComparisonRules->RemoveComparisonStep(comparisonDataIndex))
|
||||
{
|
||||
MarkFileChanged();
|
||||
RebuildComparisonDataCardList();
|
||||
}
|
||||
}
|
||||
|
||||
void RulesTabWidget::MoveComparisonStep(size_t startingIndex, size_t destinationIndex)
|
||||
{
|
||||
if (!m_selectedComparisonRules)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
if (m_selectedComparisonRules->MoveComparisonStep(startingIndex, destinationIndex))
|
||||
{
|
||||
MarkFileChanged();
|
||||
RebuildComparisonDataCardList();
|
||||
}
|
||||
}
|
||||
|
||||
void RulesTabWidget::OnAnyTokenNameChanged(size_t comparisonDataIndex)
|
||||
{
|
||||
if (comparisonDataIndex >= m_comparisonDataCardList.size() - 1)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
for (size_t i = comparisonDataIndex + 1; i < m_comparisonDataCardList.size(); ++i)
|
||||
{
|
||||
m_comparisonDataCardList[i]->GetComparisonDataWidget()->UpdateListOfTokenNames();
|
||||
}
|
||||
}
|
||||
|
||||
void RulesTabWidget::OnComparisonDataCardContextMenuRequested(size_t comparisonDataIndex, const QPoint& position)
|
||||
{
|
||||
if (!m_selectedComparisonRules)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
QMenu menu;
|
||||
|
||||
QAction* moveUpAction = new QAction(tr("Move Up"), this);
|
||||
moveUpAction->setEnabled(comparisonDataIndex > 0);
|
||||
connect(moveUpAction, &QAction::triggered, this, [=]() { MoveComparisonStep(comparisonDataIndex, comparisonDataIndex - 1); });
|
||||
menu.addAction(moveUpAction);
|
||||
|
||||
QAction* moveDownAction = new QAction(tr("Move Down"), this);
|
||||
moveDownAction->setEnabled(comparisonDataIndex < m_selectedComparisonRules->GetNumComparisonSteps() - 1);
|
||||
connect(moveDownAction, &QAction::triggered, this, [=]() { MoveComparisonStep(comparisonDataIndex, comparisonDataIndex + 2); });
|
||||
menu.addAction(moveDownAction);
|
||||
|
||||
QAction* separator = new QAction(this);
|
||||
separator->setSeparator(true);
|
||||
menu.addAction(separator);
|
||||
|
||||
QAction* deleteAction = new QAction(tr("Remove Comparison Step"), this);
|
||||
connect(deleteAction, &QAction::triggered, this, [=]() { RemoveComparisonStep(comparisonDataIndex); });
|
||||
menu.addAction(deleteAction);
|
||||
|
||||
menu.exec(position);
|
||||
}
|
||||
|
||||
} // namespace AssetBundler
|
||||
|
||||
#include <source/ui/moc_RulesTabWidget.cpp>
|
||||
@@ -0,0 +1,120 @@
|
||||
/*
|
||||
* 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.
|
||||
*
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#if !defined(Q_MOC_RUN)
|
||||
#include <source/ui/AssetBundlerTabWidget.h>
|
||||
|
||||
#include <AzCore/std/smart_ptr/shared_ptr.h>
|
||||
|
||||
#include <QAction>
|
||||
#include <QModelIndex>
|
||||
#include <QSharedPointer>
|
||||
#include <QString>
|
||||
#include <QWidget>
|
||||
#endif
|
||||
|
||||
namespace Ui
|
||||
{
|
||||
class RulesTabWidget;
|
||||
}
|
||||
|
||||
class QItemSelection;
|
||||
|
||||
namespace AzToolsFramework
|
||||
{
|
||||
class AssetFileInfoListComparison;
|
||||
}
|
||||
|
||||
namespace AssetBundler
|
||||
{
|
||||
class GUIApplicationManager;
|
||||
|
||||
class RulesFileTableModel;
|
||||
|
||||
class ComparisonDataCard;
|
||||
|
||||
class ComparisonDataWidget;
|
||||
|
||||
class RulesTabWidget
|
||||
: public AssetBundlerTabWidget
|
||||
{
|
||||
Q_OBJECT
|
||||
|
||||
public:
|
||||
explicit RulesTabWidget(QWidget* parent, GUIApplicationManager* guiApplicationManager);
|
||||
virtual ~RulesTabWidget() {}
|
||||
|
||||
QString GetTabTitle() override { return tr("Rules"); }
|
||||
|
||||
QString GetFileTypeDisplayName() override { return tr("Rules file"); }
|
||||
|
||||
AssetBundlingFileType GetFileType() override { return AssetBundlingFileType::RulesFileType; }
|
||||
|
||||
bool HasUnsavedChanges() override;
|
||||
|
||||
void Reload() override;
|
||||
|
||||
bool SaveCurrentSelection() override;
|
||||
|
||||
bool SaveAll() override;
|
||||
|
||||
void SetModelDataSource() override;
|
||||
|
||||
AzQtComponents::TableView* GetFileTableView() override;
|
||||
|
||||
QModelIndex GetSelectedFileTableIndex() override;
|
||||
|
||||
AssetBundlerAbstractFileTableModel* GetFileTableModel() override;
|
||||
|
||||
void SetActiveProjectLabel(const QString& labelText) override;
|
||||
|
||||
void ApplyConfig() override;
|
||||
|
||||
void FileSelectionChanged(const QItemSelection& /*selected*/ = QItemSelection(), const QItemSelection& /*deselected*/ = QItemSelection()) override;
|
||||
|
||||
private:
|
||||
void OnNewFileButtonPressed();
|
||||
|
||||
void OnRunRuleButtonPressed();
|
||||
|
||||
void MarkFileChanged();
|
||||
|
||||
void RebuildComparisonDataCardList();
|
||||
|
||||
void PopulateComparisonDataCardList();
|
||||
|
||||
void CreateComparisonDataCard(AZStd::shared_ptr<AzToolsFramework::AssetFileInfoListComparison> comparisonList, size_t comparisonDataIndex);
|
||||
|
||||
void RemoveAllComparisonDataCards();
|
||||
|
||||
void AddNewComparisonStep();
|
||||
|
||||
void RemoveComparisonStep(size_t comparisonDataIndex);
|
||||
|
||||
void MoveComparisonStep(size_t startingIndex, size_t destinationIndex);
|
||||
|
||||
void OnAnyTokenNameChanged(size_t comparisonDataIndex);
|
||||
|
||||
QSharedPointer<Ui::RulesTabWidget> m_ui;
|
||||
|
||||
QSharedPointer<RulesFileTableModel> m_fileTableModel;
|
||||
QModelIndex m_selectedFileTableIndex;
|
||||
AZStd::shared_ptr<AzToolsFramework::AssetFileInfoListComparison> m_selectedComparisonRules;
|
||||
|
||||
AZStd::vector<ComparisonDataCard*> m_comparisonDataCardList;
|
||||
|
||||
private slots:
|
||||
void OnComparisonDataCardContextMenuRequested(size_t comparisonDataIndex, const QPoint& position);
|
||||
};
|
||||
} // namespace AssetBundler
|
||||
@@ -0,0 +1,312 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<ui version="4.0">
|
||||
<class>RulesTabWidget</class>
|
||||
<widget class="QWidget" name="RulesTabWidget">
|
||||
<property name="geometry">
|
||||
<rect>
|
||||
<x>0</x>
|
||||
<y>0</y>
|
||||
<width>1180</width>
|
||||
<height>728</height>
|
||||
</rect>
|
||||
</property>
|
||||
<property name="windowTitle">
|
||||
<string>Rules Tab Widget</string>
|
||||
</property>
|
||||
<layout class="QVBoxLayout" name="mainVerticalLayout">
|
||||
<item>
|
||||
<layout class="QHBoxLayout" name="projectLabelHorizontalLayout">
|
||||
<item>
|
||||
<widget class="QLabel" name="activeProjectLabel"/>
|
||||
</item>
|
||||
<item>
|
||||
<spacer name="horizontalSpacer_2">
|
||||
<property name="orientation">
|
||||
<enum>Qt::Horizontal</enum>
|
||||
</property>
|
||||
<property name="sizeHint" stdset="0">
|
||||
<size>
|
||||
<width>40</width>
|
||||
<height>20</height>
|
||||
</size>
|
||||
</property>
|
||||
</spacer>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QPushButton" name="runRuleButton">
|
||||
<property name="text">
|
||||
<string>Run Selected Rule</string>
|
||||
</property>
|
||||
<property name="default">
|
||||
<bool>true</bool>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
</layout>
|
||||
</item>
|
||||
<item>
|
||||
<layout class="QHBoxLayout" name="horizontalLayout_4" stretch="0,0">
|
||||
<item>
|
||||
<widget class="QFrame" name="fileTableFrame">
|
||||
<property name="frameShape">
|
||||
<enum>QFrame::StyledPanel</enum>
|
||||
</property>
|
||||
<property name="frameShadow">
|
||||
<enum>QFrame::Raised</enum>
|
||||
</property>
|
||||
<layout class="QVBoxLayout" name="verticalLayout_5">
|
||||
<property name="leftMargin">
|
||||
<number>0</number>
|
||||
</property>
|
||||
<property name="topMargin">
|
||||
<number>0</number>
|
||||
</property>
|
||||
<property name="rightMargin">
|
||||
<number>0</number>
|
||||
</property>
|
||||
<property name="bottomMargin">
|
||||
<number>0</number>
|
||||
</property>
|
||||
<item>
|
||||
<widget class="QFrame" name="fileTableHeaderFrame">
|
||||
<property name="frameShape">
|
||||
<enum>QFrame::StyledPanel</enum>
|
||||
</property>
|
||||
<property name="frameShadow">
|
||||
<enum>QFrame::Raised</enum>
|
||||
</property>
|
||||
<layout class="QVBoxLayout" name="verticalLayout">
|
||||
<property name="leftMargin">
|
||||
<number>0</number>
|
||||
</property>
|
||||
<property name="topMargin">
|
||||
<number>0</number>
|
||||
</property>
|
||||
<property name="rightMargin">
|
||||
<number>0</number>
|
||||
</property>
|
||||
<property name="bottomMargin">
|
||||
<number>0</number>
|
||||
</property>
|
||||
<item>
|
||||
<widget class="QLabel" name="rulesFilesLabel">
|
||||
<property name="text">
|
||||
<string>Rules</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
</layout>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="AzQtComponents::FilteredSearchWidget" name="fileFilteredSearchWidget">
|
||||
<property name="placeholderText" stdset="0">
|
||||
<string>Filter by file name</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<layout class="QHBoxLayout" name="horizontalLayout_3">
|
||||
<property name="leftMargin">
|
||||
<number>5</number>
|
||||
</property>
|
||||
<property name="rightMargin">
|
||||
<number>5</number>
|
||||
</property>
|
||||
<item>
|
||||
<widget class="QPushButton" name="createNewFileButton">
|
||||
<property name="text">
|
||||
<string>+ Create new Rules file</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
</layout>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="AzQtComponents::TableView" name="fileTableView"/>
|
||||
</item>
|
||||
</layout>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QFrame" name="fileContentsFrame">
|
||||
<property name="frameShape">
|
||||
<enum>QFrame::StyledPanel</enum>
|
||||
</property>
|
||||
<property name="frameShadow">
|
||||
<enum>QFrame::Raised</enum>
|
||||
</property>
|
||||
<layout class="QVBoxLayout" name="verticalLayout_2">
|
||||
<property name="leftMargin">
|
||||
<number>0</number>
|
||||
</property>
|
||||
<property name="topMargin">
|
||||
<number>0</number>
|
||||
</property>
|
||||
<property name="rightMargin">
|
||||
<number>0</number>
|
||||
</property>
|
||||
<property name="bottomMargin">
|
||||
<number>0</number>
|
||||
</property>
|
||||
<item>
|
||||
<widget class="QFrame" name="fileContentsHeaderFrame">
|
||||
<property name="frameShape">
|
||||
<enum>QFrame::StyledPanel</enum>
|
||||
</property>
|
||||
<property name="frameShadow">
|
||||
<enum>QFrame::Raised</enum>
|
||||
</property>
|
||||
<layout class="QHBoxLayout" name="horizontalLayout">
|
||||
<property name="leftMargin">
|
||||
<number>0</number>
|
||||
</property>
|
||||
<property name="topMargin">
|
||||
<number>0</number>
|
||||
</property>
|
||||
<property name="rightMargin">
|
||||
<number>0</number>
|
||||
</property>
|
||||
<property name="bottomMargin">
|
||||
<number>0</number>
|
||||
</property>
|
||||
<item>
|
||||
<widget class="QLabel" name="comparisonRulesFileNameLabel">
|
||||
<property name="text">
|
||||
<string>Comparison Steps</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QLabel" name="rulesFileAbsolutePathLabel">
|
||||
<property name="text">
|
||||
<string/>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<spacer name="horizontalSpacer_3">
|
||||
<property name="orientation">
|
||||
<enum>Qt::Horizontal</enum>
|
||||
</property>
|
||||
<property name="sizeHint" stdset="0">
|
||||
<size>
|
||||
<width>40</width>
|
||||
<height>20</height>
|
||||
</size>
|
||||
</property>
|
||||
</spacer>
|
||||
</item>
|
||||
</layout>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<layout class="QHBoxLayout" name="horizontalLayout_5">
|
||||
<property name="rightMargin">
|
||||
<number>5</number>
|
||||
</property>
|
||||
<item>
|
||||
<spacer name="horizontalSpacer">
|
||||
<property name="orientation">
|
||||
<enum>Qt::Horizontal</enum>
|
||||
</property>
|
||||
<property name="sizeHint" stdset="0">
|
||||
<size>
|
||||
<width>40</width>
|
||||
<height>20</height>
|
||||
</size>
|
||||
</property>
|
||||
</spacer>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QPushButton" name="addComparisonStepButton">
|
||||
<property name="text">
|
||||
<string>+ Add Step</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
</layout>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QScrollArea" name="comparisonDataList">
|
||||
<property name="widgetResizable">
|
||||
<bool>true</bool>
|
||||
</property>
|
||||
<property name="alignment">
|
||||
<set>Qt::AlignLeading|Qt::AlignLeft|Qt::AlignTop</set>
|
||||
</property>
|
||||
<widget class="QWidget" name="comparisonDataListContents">
|
||||
<property name="geometry">
|
||||
<rect>
|
||||
<x>0</x>
|
||||
<y>0</y>
|
||||
<width>573</width>
|
||||
<height>614</height>
|
||||
</rect>
|
||||
</property>
|
||||
<property name="sizePolicy">
|
||||
<sizepolicy hsizetype="Preferred" vsizetype="Expanding">
|
||||
<horstretch>0</horstretch>
|
||||
<verstretch>0</verstretch>
|
||||
</sizepolicy>
|
||||
</property>
|
||||
<layout class="QVBoxLayout" name="verticalLayout_3">
|
||||
<property name="spacing">
|
||||
<number>12</number>
|
||||
</property>
|
||||
<property name="leftMargin">
|
||||
<number>10</number>
|
||||
</property>
|
||||
<property name="topMargin">
|
||||
<number>10</number>
|
||||
</property>
|
||||
<property name="rightMargin">
|
||||
<number>10</number>
|
||||
</property>
|
||||
<property name="bottomMargin">
|
||||
<number>0</number>
|
||||
</property>
|
||||
<item>
|
||||
<layout class="QVBoxLayout" name="comparisonDataListLayout"/>
|
||||
</item>
|
||||
<item>
|
||||
<spacer name="verticalSpacer">
|
||||
<property name="orientation">
|
||||
<enum>Qt::Vertical</enum>
|
||||
</property>
|
||||
<property name="sizeHint" stdset="0">
|
||||
<size>
|
||||
<width>40</width>
|
||||
<height>20</height>
|
||||
</size>
|
||||
</property>
|
||||
</spacer>
|
||||
</item>
|
||||
</layout>
|
||||
</widget>
|
||||
</widget>
|
||||
</item>
|
||||
</layout>
|
||||
</widget>
|
||||
</item>
|
||||
</layout>
|
||||
</item>
|
||||
</layout>
|
||||
</widget>
|
||||
<customwidgets>
|
||||
<customwidget>
|
||||
<class>AzQtComponents::TableView</class>
|
||||
<extends>QTreeView</extends>
|
||||
<header location="global">AzQtComponents/Components/Widgets/TableView.h</header>
|
||||
<container>1</container>
|
||||
</customwidget>
|
||||
<customwidget>
|
||||
<class>AzQtComponents::FilteredSearchWidget</class>
|
||||
<extends>QTreeView</extends>
|
||||
<header location="global">AzQtComponents/Components/FilteredSearchWidget.h</header>
|
||||
<container>1</container>
|
||||
</customwidget>
|
||||
</customwidgets>
|
||||
<resources/>
|
||||
<connections/>
|
||||
</ui>
|
||||
@@ -0,0 +1,453 @@
|
||||
/*
|
||||
* 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 <source/ui/SeedTabWidget.h>
|
||||
#include <source/ui/ui_SeedTabWidget.h>
|
||||
|
||||
#include <source/utils/GUIApplicationManager.h>
|
||||
#include <source/ui/AddSeedDialog.h>
|
||||
#include <source/ui/EditSeedDialog.h>
|
||||
#include <source/ui/NewFileDialog.h>
|
||||
#include <source/models/SeedListFileTableModel.h>
|
||||
#include <source/models/SeedListTableModel.h>
|
||||
|
||||
#include <AzCore/Outcome/Outcome.h>
|
||||
#include <AzCore/Utils/Utils.h>
|
||||
#include <AzFramework/StringFunc/StringFunc.h>
|
||||
#include <AzQtComponents/Components/FilteredSearchWidget.h>
|
||||
#include <AzToolsFramework/Asset/AssetSeedManager.h>
|
||||
#include <AzToolsFramework/AssetCatalog/PlatformAddressedAssetCatalog.h>
|
||||
|
||||
#include <QCheckBox>
|
||||
#include <QFileDialog>
|
||||
#include <QItemSelection>
|
||||
#include <QItemSelectionRange>
|
||||
#include <QMessageBox>
|
||||
#include <QPushButton>
|
||||
|
||||
|
||||
const char GenerateAssetListFilesDialogName[] = "Generate Asset List Files";
|
||||
|
||||
const int CheckBoxTableIndentationSize = 2; // when the indentation is 0, the checkboxes are too close to the edge
|
||||
|
||||
namespace AssetBundler
|
||||
{
|
||||
SeedTabWidget::SeedTabWidget(QWidget* parent, GUIApplicationManager* guiApplicationManager, const QString& assetBundlingDirectory)
|
||||
: AssetBundlerTabWidget(parent, guiApplicationManager)
|
||||
, m_fileTableModel(new SeedListFileTableModel(this))
|
||||
, m_seedListContentsModel(new SeedListTableModel())
|
||||
{
|
||||
AZ_UNUSED(assetBundlingDirectory);
|
||||
|
||||
m_ui.reset(new Ui::SeedTabWidget);
|
||||
m_ui->setupUi(this);
|
||||
|
||||
m_ui->mainVerticalLayout->setContentsMargins(MarginSize, MarginSize, MarginSize, MarginSize);
|
||||
|
||||
AZ::Debug::TraceMessageBus::Handler::BusConnect();
|
||||
|
||||
// File view of all Seed List Files
|
||||
m_fileTableFilterModel.reset(new AssetBundlerFileTableFilterModel(this, m_fileTableModel->GetFileNameColumnIndex(), m_fileTableModel->GetTimeStampColumnIndex()));
|
||||
|
||||
m_fileTableFilterModel->setSourceModel(m_fileTableModel.data());
|
||||
m_ui->fileTableView->setModel(m_fileTableFilterModel.data());
|
||||
connect(m_ui->fileFilteredSearchWidget, &AzQtComponents::FilteredSearchWidget::TextFilterChanged,
|
||||
m_fileTableFilterModel.data(), static_cast<void (QSortFilterProxyModel::*)(const QString&)>(&AssetBundlerFileTableFilterModel::FilterChanged));
|
||||
|
||||
connect(m_ui->fileTableView->selectionModel(), &QItemSelectionModel::selectionChanged, this, &SeedTabWidget::FileSelectionChanged);
|
||||
|
||||
m_ui->fileTableView->setIndentation(CheckBoxTableIndentationSize);
|
||||
|
||||
// New File Button
|
||||
connect(m_ui->createNewSeedListButton, &QPushButton::clicked, this, &SeedTabWidget::OnNewFileButtonPressed);
|
||||
|
||||
// Select Default Seed Lists
|
||||
connect(m_ui->selectDefaultSeedListsCheckBox, &QCheckBox::clicked, this, &SeedTabWidget::OnSelectDefaultSeedListsCheckBoxChanged);
|
||||
|
||||
// Generate Asset Lists Button
|
||||
SetGenerateAssetListsButtonEnabled(false);
|
||||
connect(m_ui->generateAssetListsButton, &QPushButton::clicked, this, &SeedTabWidget::OnGenerateAssetListsButtonPressed);
|
||||
|
||||
// Table that displays the contents of a Seed List File
|
||||
m_seedListContentsFilterModel.reset(new AssetBundlerFileTableFilterModel(this, SeedListTableModel::Column::ColumnRelativePath));
|
||||
|
||||
m_seedListContentsFilterModel->setSourceModel(m_seedListContentsModel.data());
|
||||
m_ui->seedFileContentsTable->setModel(m_seedListContentsFilterModel.data());
|
||||
connect(m_ui->seedListContentsFilteredSearchWidget, &AzQtComponents::FilteredSearchWidget::TextFilterChanged,
|
||||
m_seedListContentsFilterModel.data(), static_cast<void (QSortFilterProxyModel::*)(const QString&)>(&AssetBundlerFileTableFilterModel::FilterChanged));
|
||||
|
||||
m_ui->seedFileContentsTable->setContextMenuPolicy(Qt::CustomContextMenu);
|
||||
connect(m_ui->seedFileContentsTable, &QTreeView::customContextMenuRequested, this, &SeedTabWidget::OnSeedListContentsTableContextMenuRequested);
|
||||
|
||||
m_ui->seedFileContentsTable->setIndentation(0);
|
||||
|
||||
// Edit All Platforms
|
||||
connect(m_ui->editAllSeedsButton, &QPushButton::clicked, this, &SeedTabWidget::OnEditAllButtonPressed);
|
||||
|
||||
// Add Seed
|
||||
connect(m_ui->addSeedButton, &QPushButton::clicked, this, &SeedTabWidget::OnAddSeedButtonPressed);
|
||||
|
||||
SetModelDataSource();
|
||||
}
|
||||
|
||||
SeedTabWidget::~SeedTabWidget()
|
||||
{
|
||||
AZ::Debug::TraceMessageBus::Handler::BusDisconnect();
|
||||
}
|
||||
|
||||
bool SeedTabWidget::HasUnsavedChanges()
|
||||
{
|
||||
return m_fileTableModel->HasUnsavedChanges();
|
||||
}
|
||||
|
||||
void SeedTabWidget::Reload()
|
||||
{
|
||||
// Reload all the seed list files
|
||||
m_fileTableModel->Reload(AzToolsFramework::AssetSeedManager::GetSeedFileExtension(), m_watchedFolders, m_watchedFiles, m_filePathToGemNameMap);
|
||||
|
||||
// Update the selected row
|
||||
FileSelectionChanged();
|
||||
}
|
||||
|
||||
bool SeedTabWidget::SaveCurrentSelection()
|
||||
{
|
||||
return m_fileTableModel->Save(m_selectedFileTableIndex);
|
||||
}
|
||||
|
||||
bool SeedTabWidget::SaveAll()
|
||||
{
|
||||
return m_fileTableModel->SaveAll();
|
||||
}
|
||||
|
||||
void SeedTabWidget::SetModelDataSource()
|
||||
{
|
||||
// Remove the current watched folders and files
|
||||
m_guiApplicationManager->RemoveWatchedPaths(m_watchedFolders + m_watchedFiles);
|
||||
|
||||
// Set the new watched folders for the model
|
||||
m_watchedFolders.clear();
|
||||
m_watchedFolders.insert(m_guiApplicationManager->GetSeedListsFolder().c_str());
|
||||
|
||||
// Get the list of default Seed List files
|
||||
m_filePathToGemNameMap = AssetBundler::GetDefaultSeedListFiles(GetCachedEngineRoot().c_str(), m_guiApplicationManager->GetCurrentProjectName(),
|
||||
m_guiApplicationManager->GetGemInfoList(), m_guiApplicationManager->GetEnabledPlatforms());
|
||||
|
||||
// Get the list of default Seeds that are not stored in a Seed List file on-disk
|
||||
AZStd::vector<AZStd::string> defaultSeeds = GetDefaultSeeds(AZ::Utils::GetProjectPath(), m_guiApplicationManager->GetCurrentProjectName());
|
||||
m_fileTableModel->AddDefaultSeedsToInMemoryList(defaultSeeds, m_guiApplicationManager->GetCurrentProjectName().c_str(), m_guiApplicationManager->GetEnabledPlatforms());
|
||||
|
||||
// Set the new watched filess for the model
|
||||
m_watchedFiles.clear();
|
||||
for (const auto& it : m_filePathToGemNameMap)
|
||||
{
|
||||
m_watchedFiles.insert(it.first.c_str());
|
||||
}
|
||||
|
||||
ReadScanPathsFromAssetBundlerSettings(AssetBundlingFileType::SeedListFileType);
|
||||
m_guiApplicationManager->AddWatchedPaths(m_watchedFolders + m_watchedFiles);
|
||||
}
|
||||
|
||||
AzQtComponents::TableView* SeedTabWidget::GetFileTableView()
|
||||
{
|
||||
return m_ui->fileTableView;
|
||||
}
|
||||
|
||||
QModelIndex SeedTabWidget::GetSelectedFileTableIndex()
|
||||
{
|
||||
return m_selectedFileTableIndex;
|
||||
}
|
||||
|
||||
AssetBundlerAbstractFileTableModel* SeedTabWidget::GetFileTableModel()
|
||||
{
|
||||
return m_fileTableModel.get();
|
||||
}
|
||||
|
||||
void SeedTabWidget::SetActiveProjectLabel(const QString& labelText)
|
||||
{
|
||||
m_ui->activeProjectLabel->setText(labelText);
|
||||
}
|
||||
|
||||
void SeedTabWidget::ApplyConfig()
|
||||
{
|
||||
const GUIApplicationManager::Config& config = m_guiApplicationManager->GetConfig();
|
||||
|
||||
m_ui->fileTableFrame->setFixedWidth(config.fileTableWidth);
|
||||
m_ui->fileTableView->header()->resizeSection(SeedListFileTableModel::Column::ColumnFileName, config.seedListFileNameColumnWidth);
|
||||
m_ui->fileTableView->header()->resizeSection(SeedListFileTableModel::Column::ColumnCheckBox, config.checkBoxColumnWidth);
|
||||
m_ui->fileTableView->header()->resizeSection(SeedListFileTableModel::Column::ColumnProject, config.projectNameColumnWidth);
|
||||
|
||||
m_ui->seedFileContentsTable->header()->resizeSection(SeedListTableModel::Column::ColumnRelativePath, config.seedListContentsNameColumnWidth);
|
||||
}
|
||||
|
||||
void SeedTabWidget::UncheckSelectDefaultSeedListsCheckBox()
|
||||
{
|
||||
m_ui->selectDefaultSeedListsCheckBox->setChecked(false);
|
||||
}
|
||||
|
||||
void SeedTabWidget::SetGenerateAssetListsButtonEnabled(bool isEnabled)
|
||||
{
|
||||
m_ui->generateAssetListsButton->setEnabled(isEnabled);
|
||||
}
|
||||
|
||||
bool SeedTabWidget::OnPreError(const char* /*window*/, const char* /*fileName*/, int /*line*/, const char* /*func*/, const char* /*message*/)
|
||||
{
|
||||
m_hasWarnings = true;
|
||||
return false;
|
||||
}
|
||||
|
||||
bool SeedTabWidget::OnPreWarning(const char* /*window*/, const char* /*fileName*/, int /*line*/, const char* /*func*/, const char* /*message*/)
|
||||
{
|
||||
m_hasWarnings = true;
|
||||
return false;
|
||||
}
|
||||
|
||||
void SeedTabWidget::FileSelectionChanged(const QItemSelection& /*selected*/, const QItemSelection& /*deselected*/)
|
||||
{
|
||||
if (m_ui->fileTableView->selectionModel()->selectedRows().size() == 0)
|
||||
{
|
||||
// Set selected index to an invalid value
|
||||
m_selectedFileTableIndex = QModelIndex();
|
||||
m_ui->seedListFileAbsolutePathLabel->clear();
|
||||
return;
|
||||
}
|
||||
|
||||
m_selectedFileTableIndex = m_fileTableFilterModel->mapToSource(m_ui->fileTableView->selectionModel()->currentIndex());
|
||||
|
||||
m_seedListContentsModel = m_fileTableModel->GetSeedListFileContents(m_selectedFileTableIndex);
|
||||
m_seedListContentsFilterModel->setSourceModel(m_seedListContentsModel.data());
|
||||
|
||||
m_ui->seedListFileAbsolutePathLabel->setText(m_fileTableModel->GetFileAbsolutePath(m_selectedFileTableIndex).c_str());
|
||||
}
|
||||
|
||||
void SeedTabWidget::OnNewFileButtonPressed()
|
||||
{
|
||||
AZStd::string absoluteFilePath = NewFileDialog::OSNewFileDialog(
|
||||
this,
|
||||
AzToolsFramework::AssetSeedManager::GetSeedFileExtension(),
|
||||
"Seed List",
|
||||
m_guiApplicationManager->GetSeedListsFolder());
|
||||
|
||||
if (absoluteFilePath.empty())
|
||||
{
|
||||
// User canceled out of the file dialog
|
||||
return;
|
||||
}
|
||||
|
||||
AZStd::vector<AZStd::string> createdFiles = m_fileTableModel->CreateNewFiles(
|
||||
absoluteFilePath,
|
||||
AzFramework::PlatformFlags::Platform_NONE,
|
||||
QString(m_guiApplicationManager->GetCurrentProjectName().c_str()));
|
||||
|
||||
if (!createdFiles.empty())
|
||||
{
|
||||
AddScanPathToAssetBundlerSettings(AssetBundlingFileType::SeedListFileType, createdFiles.at(0));
|
||||
}
|
||||
}
|
||||
|
||||
void SeedTabWidget::OnSelectDefaultSeedListsCheckBoxChanged()
|
||||
{
|
||||
m_fileTableModel->SelectDefaultSeedLists(m_ui->selectDefaultSeedListsCheckBox->isChecked());
|
||||
}
|
||||
|
||||
void SeedTabWidget::OnGenerateAssetListsButtonPressed()
|
||||
{
|
||||
m_generateAssetListsDialog.reset(
|
||||
new NewFileDialog(
|
||||
this,
|
||||
GenerateAssetListFilesDialogName,
|
||||
QString(m_guiApplicationManager->GetAssetListsFolder().c_str()),
|
||||
AzToolsFramework::AssetSeedManager::GetAssetListFileExtension(),
|
||||
QString(tr("Asset List (*.%1)")).arg(AzToolsFramework::AssetSeedManager::GetAssetListFileExtension()),
|
||||
m_guiApplicationManager->GetEnabledPlatforms()));
|
||||
auto dialogResponse = m_generateAssetListsDialog->exec();
|
||||
if (dialogResponse == QDialog::DialogCode::Rejected)
|
||||
{
|
||||
// User canceled the operation
|
||||
return;
|
||||
}
|
||||
|
||||
m_hasWarnings = false;
|
||||
auto createdFiles = m_fileTableModel->GenerateAssetLists(m_generateAssetListsDialog->GetAbsoluteFilePath(), m_generateAssetListsDialog->GetPlatformFlags());
|
||||
|
||||
// Warnings will not prevent the generation of Asset List files, we must track them separately
|
||||
NewFileDialog::FileGenerationResultMessageBox(this, createdFiles, m_hasWarnings);
|
||||
|
||||
if (createdFiles.empty())
|
||||
{
|
||||
// Error has already been thrown
|
||||
return;
|
||||
}
|
||||
|
||||
// Add created files to the file watcher
|
||||
for (const AZStd::string& absolutePath : createdFiles)
|
||||
{
|
||||
AddScanPathToAssetBundlerSettings(AssetBundlingFileType::AssetListFileType, absolutePath);
|
||||
}
|
||||
|
||||
// The watched files list was updated after the files were created, so we need to force-reload them
|
||||
m_guiApplicationManager->UpdateFiles(AssetBundlingFileType::AssetListFileType, createdFiles);
|
||||
}
|
||||
|
||||
void SeedTabWidget::OnEditSeedButtonPressed()
|
||||
{
|
||||
if (!m_selectedFileTableIndex.isValid())
|
||||
{
|
||||
AZ_Error(AssetBundler::AppWindowName, false, "Cannot perform Edit Seed operation: No Seed List File is selected");
|
||||
return;
|
||||
}
|
||||
|
||||
// Get the current platforms of the selected Seed so we can display them as already checked
|
||||
QModelIndex currentSeedIndex = m_seedListContentsFilterModel->mapToSource(m_ui->seedFileContentsTable->selectionModel()->currentIndex());
|
||||
auto getPlatformOutcome = m_seedListContentsModel->GetSeedPlatforms(currentSeedIndex);
|
||||
if (!getPlatformOutcome.IsSuccess())
|
||||
{
|
||||
// Error has already been thrown
|
||||
return;
|
||||
}
|
||||
|
||||
// Create and display the Edit Seed dialog
|
||||
m_editSeedDialog.reset(new EditSeedDialog(this, m_guiApplicationManager->GetEnabledPlatforms(), getPlatformOutcome.GetValue()));
|
||||
auto dialogResponse = m_editSeedDialog->exec();
|
||||
if (dialogResponse == QDialog::DialogCode::Rejected)
|
||||
{
|
||||
// User canceled the operation
|
||||
return;
|
||||
}
|
||||
|
||||
// Set the data in the model
|
||||
m_fileTableModel->SetSeedPlatforms(m_selectedFileTableIndex, currentSeedIndex, m_editSeedDialog->GetPlatformFlags());
|
||||
}
|
||||
|
||||
void SeedTabWidget::OnEditAllButtonPressed()
|
||||
{
|
||||
if (!m_selectedFileTableIndex.isValid())
|
||||
{
|
||||
AZ_Error(AssetBundler::AppWindowName, false, "Cannot perform Edit All operation: No Seed List File is selected");
|
||||
return;
|
||||
}
|
||||
|
||||
// Get the platforms of all the seeds so we can display them as already checked or partially checked
|
||||
AzFramework::PlatformFlags selectedPlatformFlags = AzFramework::PlatformFlags::AllNamedPlatforms;
|
||||
AzFramework::PlatformFlags partiallySelectedPlatformFlags = AzFramework::PlatformFlags::Platform_NONE;
|
||||
QMap<QModelIndex, AzFramework::PlatformFlags> indexToPlatformFlagsMap;
|
||||
for (int row = 0; row < m_seedListContentsModel->rowCount(); ++row)
|
||||
{
|
||||
QModelIndex currentSeedIndex = m_seedListContentsModel->index(row, 0);
|
||||
auto getPlatformOutcome = m_seedListContentsModel->GetSeedPlatforms(currentSeedIndex);
|
||||
if (!getPlatformOutcome.IsSuccess())
|
||||
{
|
||||
// Error has already been thrown
|
||||
return;
|
||||
}
|
||||
|
||||
indexToPlatformFlagsMap[currentSeedIndex] = getPlatformOutcome.TakeValue();
|
||||
selectedPlatformFlags &= indexToPlatformFlagsMap[currentSeedIndex];
|
||||
partiallySelectedPlatformFlags |= selectedPlatformFlags ^ indexToPlatformFlagsMap[currentSeedIndex];
|
||||
}
|
||||
|
||||
// Create and display the Edit Seed dialog
|
||||
m_editSeedDialog.reset(new EditSeedDialog(
|
||||
this,
|
||||
m_guiApplicationManager->GetEnabledPlatforms(),
|
||||
selectedPlatformFlags,
|
||||
partiallySelectedPlatformFlags));
|
||||
|
||||
auto dialogResponse = m_editSeedDialog->exec();
|
||||
if (dialogResponse == QDialog::DialogCode::Rejected)
|
||||
{
|
||||
// User canceled the operation
|
||||
return;
|
||||
}
|
||||
|
||||
// Set the data in the model
|
||||
for (int row = 0; row < m_seedListContentsModel->rowCount(); ++row)
|
||||
{
|
||||
QModelIndex currentSeedIndex = m_seedListContentsModel->index(row, 0);
|
||||
AzFramework::PlatformFlags checkedPlatforms = m_editSeedDialog->GetPlatformFlags();
|
||||
AzFramework::PlatformFlags partiallyCheckedPlatforms = m_editSeedDialog->GetPartiallySelectedPlatformFlags();
|
||||
// If the platform is partially checked, we want to keep its original status when saving the changes
|
||||
AzFramework::PlatformFlags platformFlags = indexToPlatformFlagsMap[currentSeedIndex] & partiallyCheckedPlatforms | checkedPlatforms;
|
||||
|
||||
m_fileTableModel->SetSeedPlatforms(m_selectedFileTableIndex, currentSeedIndex, platformFlags);
|
||||
}
|
||||
}
|
||||
|
||||
void SeedTabWidget::OnAddSeedButtonPressed()
|
||||
{
|
||||
if (!m_selectedFileTableIndex.isValid())
|
||||
{
|
||||
AZ_Error(AssetBundler::AppWindowName, false, "Cannot perform Add Seed operation: No Seed List File is selected");
|
||||
return;
|
||||
}
|
||||
|
||||
// Get path to the platform-specific cache folder of one of the enabled platforms
|
||||
AzFramework::PlatformFlags enabledPlatforms = m_guiApplicationManager->GetEnabledPlatforms();
|
||||
AZStd::fixed_vector<AzFramework::PlatformId, AzFramework::PlatformId::NumPlatformIds> enabledPlatformIndices = AzFramework::PlatformHelper::GetPlatformIndicesInterpreted(enabledPlatforms);
|
||||
AZStd::string platformSpecificCachePath = AzToolsFramework::PlatformAddressedAssetCatalog::GetCatalogRegistryPathForPlatform(enabledPlatformIndices[0]);
|
||||
|
||||
// Create and display the Add Seed Dialog
|
||||
m_addSeedDialog.reset(new AddSeedDialog(this, enabledPlatforms, platformSpecificCachePath));
|
||||
auto dialogResponse = m_addSeedDialog->exec();
|
||||
if (dialogResponse == QDialog::DialogCode::Rejected)
|
||||
{
|
||||
// User canceled the operation
|
||||
return;
|
||||
}
|
||||
|
||||
// Set the data in the model
|
||||
m_fileTableModel->AddSeed(m_selectedFileTableIndex, m_addSeedDialog->GetFileName(), m_addSeedDialog->GetPlatformFlags());
|
||||
}
|
||||
|
||||
void SeedTabWidget::OnRemoveSeedButtonPressed()
|
||||
{
|
||||
if (!m_selectedFileTableIndex.isValid())
|
||||
{
|
||||
AZ_Error(AssetBundler::AppWindowName, false, "Cannot perform Remove Seed operation: No Seed List File is selected");
|
||||
return;
|
||||
}
|
||||
|
||||
// Set the data in the model
|
||||
QModelIndex currentSeedIndex = m_seedListContentsFilterModel->mapToSource(m_ui->seedFileContentsTable->selectionModel()->currentIndex());
|
||||
m_fileTableModel->RemoveSeed(m_selectedFileTableIndex, currentSeedIndex);
|
||||
}
|
||||
|
||||
void SeedTabWidget::OnSeedListContentsTableContextMenuRequested(const QPoint& pos)
|
||||
{
|
||||
if (!m_selectedFileTableIndex.isValid())
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
QMenu* contextMenu = new QMenu(this);
|
||||
contextMenu->setToolTipsVisible(true);
|
||||
|
||||
QAction* action = contextMenu->addAction(tr("Edit Platforms"));
|
||||
connect(action, &QAction::triggered, this, &SeedTabWidget::OnEditSeedButtonPressed);
|
||||
action->setToolTip(tr("Change what platforms are referenced when generating an Asset List file."));
|
||||
|
||||
contextMenu->addSeparator();
|
||||
|
||||
action = contextMenu->addAction(tr("Add Seed"));
|
||||
connect(action, &QAction::triggered, this, &SeedTabWidget::OnAddSeedButtonPressed);
|
||||
action->setToolTip(tr("Add a new Seed to the Seed List file."));
|
||||
|
||||
action = contextMenu->addAction(tr("Remove Seed"));
|
||||
connect(action, &QAction::triggered, this, &SeedTabWidget::OnRemoveSeedButtonPressed);
|
||||
action->setToolTip(tr("Removes the Seed from the Seed List file."));
|
||||
|
||||
contextMenu->exec(m_ui->seedFileContentsTable->mapToGlobal(pos));
|
||||
delete contextMenu;
|
||||
}
|
||||
|
||||
} //namespace AssetBundler
|
||||
|
||||
#include <source/ui/moc_SeedTabWidget.cpp>
|
||||
@@ -0,0 +1,129 @@
|
||||
/*
|
||||
* 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.
|
||||
*
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#if !defined(Q_MOC_RUN)
|
||||
#include <source/ui/AssetBundlerTabWidget.h>
|
||||
|
||||
#include <AzCore/Debug/TraceMessageBus.h>
|
||||
#include <AzCore/std/smart_ptr/unique_ptr.h>
|
||||
#include <AzFramework/Platform/PlatformDefaults.h>
|
||||
|
||||
#include <QDir>
|
||||
#include <QItemSelectionModel>
|
||||
#include <QModelIndex>
|
||||
#include <QSharedPointer>
|
||||
#include <QString>
|
||||
#include <QWidget>
|
||||
#endif
|
||||
|
||||
namespace Ui
|
||||
{
|
||||
class SeedTabWidget;
|
||||
}
|
||||
|
||||
class QFileSystemModel;
|
||||
class QStringListModel;
|
||||
|
||||
namespace AssetBundler
|
||||
{
|
||||
class GUIApplicationManager;
|
||||
|
||||
class SeedListFileTableModel;
|
||||
class SeedListTableModel;
|
||||
|
||||
class NewFileDialog;
|
||||
class EditSeedDialog;
|
||||
class AddSeedDialog;
|
||||
|
||||
class SeedTabWidget
|
||||
: public AssetBundlerTabWidget
|
||||
, public AZ::Debug::TraceMessageBus::Handler
|
||||
{
|
||||
Q_OBJECT
|
||||
|
||||
public:
|
||||
explicit SeedTabWidget(QWidget* parent, GUIApplicationManager* guiApplicationManager, const QString& assetBundlingDirectory);
|
||||
virtual ~SeedTabWidget();
|
||||
|
||||
QString GetTabTitle() override { return tr("Seeds"); }
|
||||
|
||||
QString GetFileTypeDisplayName() override { return tr("Seed List file"); }
|
||||
|
||||
AssetBundlingFileType GetFileType() override { return AssetBundlingFileType::SeedListFileType; }
|
||||
|
||||
bool HasUnsavedChanges() override;
|
||||
|
||||
void Reload() override;
|
||||
|
||||
bool SaveCurrentSelection() override;
|
||||
|
||||
bool SaveAll() override;
|
||||
|
||||
void SetModelDataSource() override;
|
||||
|
||||
AzQtComponents::TableView* GetFileTableView() override;
|
||||
|
||||
QModelIndex GetSelectedFileTableIndex() override;
|
||||
|
||||
AssetBundlerAbstractFileTableModel* GetFileTableModel() override;
|
||||
|
||||
void SetActiveProjectLabel(const QString& labelText) override;
|
||||
|
||||
void ApplyConfig() override;
|
||||
|
||||
void FileSelectionChanged(const QItemSelection& /*selected*/ = QItemSelection(), const QItemSelection& /*deselected*/ = QItemSelection()) override;
|
||||
|
||||
void UncheckSelectDefaultSeedListsCheckBox();
|
||||
|
||||
void SetGenerateAssetListsButtonEnabled(bool isEnabled);
|
||||
|
||||
/////////////////////////////////////////////////////////
|
||||
// TraceMessageBus overrides
|
||||
bool OnPreError(const char* window, const char* fileName, int line, const char* func, const char* message) override;
|
||||
bool OnPreWarning(const char* window, const char* fileName, int line, const char* func, const char* message) override;
|
||||
/////////////////////////////////////////////////////////
|
||||
|
||||
private:
|
||||
|
||||
void OnNewFileButtonPressed();
|
||||
|
||||
void OnSelectDefaultSeedListsCheckBoxChanged();
|
||||
|
||||
void OnGenerateAssetListsButtonPressed();
|
||||
|
||||
void OnEditSeedButtonPressed();
|
||||
void OnEditAllButtonPressed();
|
||||
|
||||
void OnAddSeedButtonPressed();
|
||||
void OnRemoveSeedButtonPressed();
|
||||
|
||||
void OnSeedListContentsTableContextMenuRequested(const QPoint& pos);
|
||||
|
||||
QSharedPointer<Ui::SeedTabWidget> m_ui;
|
||||
QDir m_assetBundlingFolder;
|
||||
|
||||
QSharedPointer<SeedListFileTableModel> m_fileTableModel;
|
||||
QModelIndex m_selectedFileTableIndex;
|
||||
|
||||
QSharedPointer<NewFileDialog> m_generateAssetListsDialog;
|
||||
|
||||
QSharedPointer<AssetBundler::AssetBundlerFileTableFilterModel> m_seedListContentsFilterModel;
|
||||
QSharedPointer<SeedListTableModel> m_seedListContentsModel;
|
||||
|
||||
QSharedPointer<EditSeedDialog> m_editSeedDialog;
|
||||
QSharedPointer<AddSeedDialog> m_addSeedDialog;
|
||||
|
||||
bool m_hasWarnings = false;
|
||||
};
|
||||
} // namespace AssetBundler
|
||||
@@ -0,0 +1,297 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<ui version="4.0">
|
||||
<class>SeedTabWidget</class>
|
||||
<widget class="QWidget" name="SeedTabWidget">
|
||||
<property name="geometry">
|
||||
<rect>
|
||||
<x>0</x>
|
||||
<y>0</y>
|
||||
<width>813</width>
|
||||
<height>673</height>
|
||||
</rect>
|
||||
</property>
|
||||
<property name="windowTitle">
|
||||
<string>Seed Tab Widget</string>
|
||||
</property>
|
||||
<layout class="QVBoxLayout" name="mainVerticalLayout">
|
||||
<item>
|
||||
<layout class="QHBoxLayout" name="projectLabelHorizontalLayout">
|
||||
<property name="rightMargin">
|
||||
<number>0</number>
|
||||
</property>
|
||||
<item>
|
||||
<widget class="QLabel" name="activeProjectLabel"/>
|
||||
</item>
|
||||
<item>
|
||||
<spacer name="horizontalSpacer_2">
|
||||
<property name="orientation">
|
||||
<enum>Qt::Horizontal</enum>
|
||||
</property>
|
||||
<property name="sizeHint" stdset="0">
|
||||
<size>
|
||||
<width>40</width>
|
||||
<height>20</height>
|
||||
</size>
|
||||
</property>
|
||||
</spacer>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QPushButton" name="generateAssetListsButton">
|
||||
<property name="text">
|
||||
<string>Generate Asset Lists</string>
|
||||
</property>
|
||||
<property name="default">
|
||||
<bool>true</bool>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
</layout>
|
||||
</item>
|
||||
<item>
|
||||
<layout class="QHBoxLayout" name="horizontalLayout_4" stretch="0,0">
|
||||
<item>
|
||||
<widget class="QFrame" name="fileTableFrame">
|
||||
<property name="frameShape">
|
||||
<enum>QFrame::StyledPanel</enum>
|
||||
</property>
|
||||
<property name="frameShadow">
|
||||
<enum>QFrame::Raised</enum>
|
||||
</property>
|
||||
<layout class="QVBoxLayout" name="verticalLayout_4">
|
||||
<property name="leftMargin">
|
||||
<number>0</number>
|
||||
</property>
|
||||
<property name="topMargin">
|
||||
<number>0</number>
|
||||
</property>
|
||||
<property name="rightMargin">
|
||||
<number>0</number>
|
||||
</property>
|
||||
<property name="bottomMargin">
|
||||
<number>0</number>
|
||||
</property>
|
||||
<item>
|
||||
<widget class="QFrame" name="fileTableHeaderFrame">
|
||||
<property name="frameShape">
|
||||
<enum>QFrame::StyledPanel</enum>
|
||||
</property>
|
||||
<property name="frameShadow">
|
||||
<enum>QFrame::Raised</enum>
|
||||
</property>
|
||||
<layout class="QVBoxLayout" name="verticalLayout_5">
|
||||
<property name="leftMargin">
|
||||
<number>0</number>
|
||||
</property>
|
||||
<property name="topMargin">
|
||||
<number>0</number>
|
||||
</property>
|
||||
<property name="rightMargin">
|
||||
<number>0</number>
|
||||
</property>
|
||||
<property name="bottomMargin">
|
||||
<number>0</number>
|
||||
</property>
|
||||
<item>
|
||||
<widget class="QLabel" name="seedListsLabel">
|
||||
<property name="text">
|
||||
<string>Seed List files</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
</layout>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="AzQtComponents::FilteredSearchWidget" name="fileFilteredSearchWidget">
|
||||
<property name="placeholderText" stdset="0">
|
||||
<string>Filter by file name</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<layout class="QHBoxLayout" name="horizontalLayout_5">
|
||||
<property name="leftMargin">
|
||||
<number>5</number>
|
||||
</property>
|
||||
<property name="rightMargin">
|
||||
<number>5</number>
|
||||
</property>
|
||||
<item>
|
||||
<widget class="QPushButton" name="createNewSeedListButton">
|
||||
<property name="text">
|
||||
<string>+ Create new Seed List file</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
</layout>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="AzQtComponents::TableView" name="fileTableView"/>
|
||||
</item>
|
||||
<item>
|
||||
<layout class="QHBoxLayout" name="horizontalLayout_3">
|
||||
<item>
|
||||
<spacer name="horizontalSpacer_3">
|
||||
<property name="orientation">
|
||||
<enum>Qt::Horizontal</enum>
|
||||
</property>
|
||||
<property name="sizeHint" stdset="0">
|
||||
<size>
|
||||
<width>40</width>
|
||||
<height>20</height>
|
||||
</size>
|
||||
</property>
|
||||
</spacer>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QCheckBox" name="selectDefaultSeedListsCheckBox">
|
||||
<property name="text">
|
||||
<string>Default Seed Lists</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
</layout>
|
||||
</item>
|
||||
</layout>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QFrame" name="fileContentsFrame">
|
||||
<property name="frameShape">
|
||||
<enum>QFrame::StyledPanel</enum>
|
||||
</property>
|
||||
<property name="frameShadow">
|
||||
<enum>QFrame::Raised</enum>
|
||||
</property>
|
||||
<layout class="QVBoxLayout" name="verticalLayout">
|
||||
<property name="leftMargin">
|
||||
<number>0</number>
|
||||
</property>
|
||||
<property name="topMargin">
|
||||
<number>0</number>
|
||||
</property>
|
||||
<property name="rightMargin">
|
||||
<number>0</number>
|
||||
</property>
|
||||
<property name="bottomMargin">
|
||||
<number>0</number>
|
||||
</property>
|
||||
<item>
|
||||
<widget class="QFrame" name="fileContentsHeaderFrame">
|
||||
<property name="frameShape">
|
||||
<enum>QFrame::StyledPanel</enum>
|
||||
</property>
|
||||
<property name="frameShadow">
|
||||
<enum>QFrame::Raised</enum>
|
||||
</property>
|
||||
<layout class="QHBoxLayout" name="horizontalLayout">
|
||||
<property name="leftMargin">
|
||||
<number>0</number>
|
||||
</property>
|
||||
<property name="topMargin">
|
||||
<number>0</number>
|
||||
</property>
|
||||
<property name="rightMargin">
|
||||
<number>0</number>
|
||||
</property>
|
||||
<property name="bottomMargin">
|
||||
<number>0</number>
|
||||
</property>
|
||||
<item>
|
||||
<widget class="QLabel" name="seedListContentsLabel">
|
||||
<property name="text">
|
||||
<string>Product Assets</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QLabel" name="seedListFileAbsolutePathLabel">
|
||||
<property name="text">
|
||||
<string/>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<spacer name="horizontalSpacer">
|
||||
<property name="orientation">
|
||||
<enum>Qt::Horizontal</enum>
|
||||
</property>
|
||||
<property name="sizeHint" stdset="0">
|
||||
<size>
|
||||
<width>40</width>
|
||||
<height>20</height>
|
||||
</size>
|
||||
</property>
|
||||
</spacer>
|
||||
</item>
|
||||
</layout>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<layout class="QHBoxLayout" name="horizontalLayout_2">
|
||||
<property name="rightMargin">
|
||||
<number>5</number>
|
||||
</property>
|
||||
<item>
|
||||
<widget class="AzQtComponents::FilteredSearchWidget" name="seedListContentsFilteredSearchWidget">
|
||||
<property name="placeholderText" stdset="0">
|
||||
<string>Filter by file name</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<spacer name="horizontalSpacer_4">
|
||||
<property name="orientation">
|
||||
<enum>Qt::Horizontal</enum>
|
||||
</property>
|
||||
<property name="sizeHint" stdset="0">
|
||||
<size>
|
||||
<width>40</width>
|
||||
<height>20</height>
|
||||
</size>
|
||||
</property>
|
||||
</spacer>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QPushButton" name="editAllSeedsButton">
|
||||
<property name="text">
|
||||
<string>Edit All</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QPushButton" name="addSeedButton">
|
||||
<property name="text">
|
||||
<string>+ Add Asset</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
</layout>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="AzQtComponents::TableView" name="seedFileContentsTable"/>
|
||||
</item>
|
||||
</layout>
|
||||
</widget>
|
||||
</item>
|
||||
</layout>
|
||||
</item>
|
||||
</layout>
|
||||
</widget>
|
||||
<customwidgets>
|
||||
<customwidget>
|
||||
<class>AzQtComponents::TableView</class>
|
||||
<extends>QTreeView</extends>
|
||||
<header location="global">AzQtComponents/Components/Widgets/TableView.h</header>
|
||||
<container>1</container>
|
||||
</customwidget>
|
||||
<customwidget>
|
||||
<class>AzQtComponents::FilteredSearchWidget</class>
|
||||
<extends>QTreeView</extends>
|
||||
<header location="global">AzQtComponents/Components/FilteredSearchWidget.h</header>
|
||||
<container>1</container>
|
||||
</customwidget>
|
||||
</customwidgets>
|
||||
<resources/>
|
||||
<connections/>
|
||||
</ui>
|
||||
@@ -0,0 +1,3 @@
|
||||
version https://git-lfs.github.com/spec/v1
|
||||
oid sha256:690a47a0e2ff4c41ce23ad0bc5dd5bd525e03676a26d3367726beaa96babf207
|
||||
size 138199
|
||||
@@ -0,0 +1,7 @@
|
||||
<RCC>
|
||||
<qresource prefix="/AssetBundler/style">
|
||||
<file>AssetBundler.qss</file>
|
||||
<file>AssetBundlerConfig.ini</file>
|
||||
<file>AssetBundler-Icon-256x256@x2.ico</file>
|
||||
</qresource>
|
||||
</RCC>
|
||||
@@ -0,0 +1,173 @@
|
||||
/*
|
||||
* 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.
|
||||
*
|
||||
*/
|
||||
|
||||
/************** General (MainWindow) **************/
|
||||
|
||||
QTabWidget:pane {
|
||||
border: none;
|
||||
}
|
||||
|
||||
QLabel#activeProjectLabel {
|
||||
font-size: 18px;
|
||||
font-family: "Amazon Ember Light";
|
||||
margin-bottom: 5px;
|
||||
}
|
||||
|
||||
QTreeView#logTableView {
|
||||
border: 1px solid #1B1B1B;
|
||||
margin-left: 10px;
|
||||
margin-right: 10px;
|
||||
margin-bottom: 10px;
|
||||
}
|
||||
|
||||
QTreeView#logTableView QHeaderView::section {
|
||||
background-color: #1B1B1B;
|
||||
}
|
||||
|
||||
/************** General (Tabs) **************/
|
||||
|
||||
QFrame#fileTableFrame,
|
||||
QFrame#fileContentsFrame {
|
||||
border: 1px solid #1B1B1B;
|
||||
}
|
||||
|
||||
QFrame#fileTableFrame {
|
||||
margin-right: 10px;
|
||||
}
|
||||
|
||||
QFrame#fileTableHeaderFrame,
|
||||
QFrame#fileContentsHeaderFrame,
|
||||
QFrame#fileTableHeaderFrame QLabel,
|
||||
QFrame#fileContentsHeaderFrame QLabel{
|
||||
background-color: #1B1B1B;
|
||||
}
|
||||
|
||||
QFrame#fileTableHeaderFrame QLabel,
|
||||
QFrame#fileContentsHeaderFrame QLabel{
|
||||
background-color: #1B1B1B;
|
||||
margin-left: 5px;
|
||||
}
|
||||
|
||||
QTabWidget QTreeView QHeaderView::section {
|
||||
background-color: rgb(77, 77, 77);
|
||||
}
|
||||
|
||||
QWidget#PlatformSelectionWidget QLabel#platformSelectionLabel {
|
||||
margin-right: 10px;
|
||||
}
|
||||
|
||||
QDialog#NewFileDialog QPushButton#browseFileButton,
|
||||
QDialog#NewFileDialog QPushButton#createFileButton,
|
||||
QDialog#NewFileDialog QPushButton#cancelButton {
|
||||
margin-left: 10px;
|
||||
margin-right: 10px;
|
||||
}
|
||||
|
||||
/************** Seeds Tab **************/
|
||||
|
||||
QWidget#SeedTabWidget QPushButton#generateAssetListsButton,
|
||||
QWidget#SeedTabWidget QPushButton#browseFileButton,
|
||||
QWidget#SeedTabWidget QPushButton#cancelButton,
|
||||
QWidget#SeedTabWidget QPushButton#addSeedButton,
|
||||
QWidget#SeedTabWidget QPushButton#applyChangesButton {
|
||||
margin-left: 10px;
|
||||
margin-right: 10px;
|
||||
}
|
||||
|
||||
QCheckBox#selectDefaultSeedListsCheckBox {
|
||||
margin: 5px;
|
||||
}
|
||||
|
||||
QWidget#seedListContentsFilteredSearchWidget {
|
||||
margin-left: 5px;
|
||||
}
|
||||
|
||||
QDialog QFrame#inputValuesFrame {
|
||||
border: none;
|
||||
margin: 10px;
|
||||
padding: 10px;
|
||||
}
|
||||
|
||||
QDialog QFrame#lineFrame {
|
||||
border: none;
|
||||
margin-top: 10px;
|
||||
margin-bottom: 10px;
|
||||
}
|
||||
|
||||
QDialog QFrame#inputValuesFrame,
|
||||
QDialog QFrame#lineFrame,
|
||||
QDialog#AddSeedDialog QLabel,
|
||||
QDialog#AddSeedDialog QCheckBox,
|
||||
QDialog#EditSeedDialog QLabel,
|
||||
QDialog#EditSeedDialog QCheckBox,
|
||||
QDialog#NewFileDialog QLabel,
|
||||
QDialog#NewFileDialog QCheckBox {
|
||||
background-color: #555555;
|
||||
}
|
||||
|
||||
/************** Asset List Tab **************/
|
||||
|
||||
QLabel#assetListContentsLabel {
|
||||
margin-right: 10px;
|
||||
}
|
||||
|
||||
QWidget#fileFilteredSearchWidget,
|
||||
QWidget#assetListContentsFilteredSearchWidget {
|
||||
margin-left: 5px;
|
||||
margin-right: 5px;
|
||||
}
|
||||
|
||||
QPushButton#generateBundleButton {
|
||||
margin-left: 10px;
|
||||
margin-right: 10px;
|
||||
}
|
||||
|
||||
/************** Generate Bundles Modal **************/
|
||||
|
||||
QFrame#bundleSettingsFrame {
|
||||
border: none;
|
||||
margin-bottom: 10px;
|
||||
}
|
||||
|
||||
QFrame#outputBundleLocationFrame,
|
||||
QFrame#bundleSettingsFileFrame {
|
||||
border: none;
|
||||
margin: 10px;
|
||||
}
|
||||
|
||||
QFrame#bundleSettingsFrame,
|
||||
QFrame#outputBundleLocationFrame,
|
||||
QFrame#bundleSettingsFileFrame,
|
||||
QFrame#bundleSettingsFrame QLabel {
|
||||
background-color: #555555;
|
||||
}
|
||||
|
||||
QWidget#GenerateBundlesModal QPushButton {
|
||||
margin-left: 10px;
|
||||
margin-right: 10px;
|
||||
}
|
||||
|
||||
/************** Rules Tab **************/
|
||||
|
||||
QPushButton#runRuleButton,
|
||||
QPushButton#addComparisonStepButton {
|
||||
margin-left: 10px;
|
||||
margin-right: 10px;
|
||||
}
|
||||
|
||||
QScrollArea#comparisonDataList {
|
||||
border: none;
|
||||
}
|
||||
|
||||
QFrame#comparisonDataFrame {
|
||||
padding: 10px;
|
||||
}
|
||||
@@ -0,0 +1,19 @@
|
||||
[ErrorLogDetails]
|
||||
LogTypeColumnWidth=180
|
||||
LogSourceColumnWidth=130
|
||||
|
||||
[GeneralFileTableDetails]
|
||||
FileTableWidth=450
|
||||
FileNameColumnWidth=250
|
||||
|
||||
[SeedsTabDetails]
|
||||
CheckBoxColumnWidth=22
|
||||
SeedListFileNameColumnWidth=150
|
||||
ProjectNameColumnWidth=120
|
||||
SeedListContentsNameColumnWidth=400
|
||||
|
||||
[AssetListsTabDetails]
|
||||
AssetListFileNameColumnWidth=210
|
||||
AssetListPlatformColumnWidth=70
|
||||
ProductAssetNameColumnWidth=220
|
||||
ProductAssetRelativePathColumnWidth=300
|
||||
@@ -0,0 +1,386 @@
|
||||
/*
|
||||
* 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 <source/utils/GUIApplicationManager.h>
|
||||
|
||||
#include <source/ui/MainWindow.h>
|
||||
#include <source/utils/utils.h>
|
||||
|
||||
#include <AzCore/IO/FileIO.h>
|
||||
#include <AzCore/Utils/Utils.h>
|
||||
#include <AzFramework/Asset/AssetCatalog.h>
|
||||
#include <AzFramework/StringFunc/StringFunc.h>
|
||||
#include <AzToolsFramework/AssetCatalog/PlatformAddressedAssetCatalogBus.h>
|
||||
|
||||
#include <AzQtComponents/Components/ConfigHelpers.h>
|
||||
#include <AzQtComponents/Components/StyleManager.h>
|
||||
#include <AzQtComponents/Components/WindowDecorationWrapper.h>
|
||||
|
||||
#include <QApplication>
|
||||
#include <QLocale>
|
||||
#include <QStringList>
|
||||
|
||||
// Forward declare platform-specific functions
|
||||
namespace Platform
|
||||
{
|
||||
/// On Windows this will return the setting for our custom title bar
|
||||
/// On other platforms this will return the setting for using platform default
|
||||
/// This ensures that functions like Exit, Maximize, and Minimize appear in the right platform-specific style
|
||||
AzQtComponents::WindowDecorationWrapper::Option GetWindowDecorationWrapperOption();
|
||||
} // namespace Platform
|
||||
|
||||
const char AssetBundlingFolderName [] = "AssetBundling";
|
||||
const char SeedListsFolderName [] = "SeedLists";
|
||||
const char AssetListsFolderName [] = "AssetLists";
|
||||
const char RulesFolderName[] = "Rules";
|
||||
const char BundleSettingsFolderName [] = "BundleSettings";
|
||||
const char BundlesFolderName [] = "Bundles";
|
||||
|
||||
namespace AssetBundler
|
||||
{
|
||||
|
||||
GUIApplicationManager::Config GUIApplicationManager::loadConfig(QSettings& settings)
|
||||
{
|
||||
using namespace AzQtComponents;
|
||||
|
||||
Config config = defaultConfig();
|
||||
|
||||
// Error Log
|
||||
{
|
||||
ConfigHelpers::GroupGuard details(&settings, QStringLiteral("ErrorLogDetails"));
|
||||
ConfigHelpers::read<int>(settings, QStringLiteral("LogTypeColumnWidth"), config.logTypeColumnWidth);
|
||||
ConfigHelpers::read<int>(settings, QStringLiteral("LogSourceColumnWidth"), config.logSourceColumnWidth);
|
||||
}
|
||||
|
||||
// General File Tables
|
||||
{
|
||||
ConfigHelpers::GroupGuard details(&settings, QStringLiteral("GeneralFileTableDetails"));
|
||||
ConfigHelpers::read<int>(settings, QStringLiteral("FileTableWidth"), config.fileTableWidth);
|
||||
ConfigHelpers::read<int>(settings, QStringLiteral("FileNameColumnWidth"), config.fileNameColumnWidth);
|
||||
}
|
||||
|
||||
// Seeds Tab
|
||||
{
|
||||
ConfigHelpers::GroupGuard details(&settings, QStringLiteral("SeedsTabDetails"));
|
||||
ConfigHelpers::read<int>(settings, QStringLiteral("CheckBoxColumnWidth"), config.checkBoxColumnWidth);
|
||||
ConfigHelpers::read<int>(settings, QStringLiteral("SeedListFileNameColumnWidth"), config.seedListFileNameColumnWidth);
|
||||
ConfigHelpers::read<int>(settings, QStringLiteral("ProjectNameColumnWidth"), config.projectNameColumnWidth);
|
||||
ConfigHelpers::read<int>(settings, QStringLiteral("SeedListContentsNameColumnWidth"), config.seedListContentsNameColumnWidth);
|
||||
}
|
||||
|
||||
// Asset Lists Tab
|
||||
{
|
||||
ConfigHelpers::GroupGuard details(&settings, QStringLiteral("AssetListsTabDetails"));
|
||||
ConfigHelpers::read<int>(settings, QStringLiteral("AssetListFileNameColumnWidth"), config.assetListFileNameColumnWidth);
|
||||
ConfigHelpers::read<int>(settings, QStringLiteral("AssetListPlatformColumnWidth"), config.assetListPlatformColumnWidth);
|
||||
ConfigHelpers::read<int>(settings, QStringLiteral("ProductAssetNameColumnWidth"), config.productAssetNameColumnWidth);
|
||||
ConfigHelpers::read<int>(settings, QStringLiteral("ProductAssetRelativePathColumnWidth"), config.productAssetRelativePathColumnWidth);
|
||||
}
|
||||
|
||||
return config;
|
||||
}
|
||||
|
||||
GUIApplicationManager::Config GUIApplicationManager::defaultConfig()
|
||||
{
|
||||
// These are used if the values can't be read from AssetBundlerConfig.ini.
|
||||
Config config;
|
||||
|
||||
config.logTypeColumnWidth = 150;
|
||||
config.logSourceColumnWidth = 150;
|
||||
|
||||
config.fileTableWidth = 250;
|
||||
config.fileNameColumnWidth = 150;
|
||||
|
||||
config.checkBoxColumnWidth = 150;
|
||||
config.seedListFileNameColumnWidth = 150;
|
||||
config.projectNameColumnWidth = 150;
|
||||
config.seedListContentsNameColumnWidth = 150;
|
||||
|
||||
config.assetListFileNameColumnWidth = 150;
|
||||
config.assetListPlatformColumnWidth = 150;
|
||||
config.productAssetNameColumnWidth = 150;
|
||||
config.productAssetRelativePathColumnWidth = 150;
|
||||
|
||||
return config;
|
||||
}
|
||||
|
||||
GUIApplicationManager::GUIApplicationManager(int* argc, char*** argv, QObject* parent)
|
||||
: ApplicationManager(argc, argv, parent)
|
||||
{
|
||||
}
|
||||
|
||||
GUIApplicationManager::~GUIApplicationManager()
|
||||
{
|
||||
// Reset this before DestroyApplication, BusDisconnect needs to happen before Application::Stop() destroys the allocators.
|
||||
m_platformCatalogManager.reset();
|
||||
}
|
||||
|
||||
bool GUIApplicationManager::Init()
|
||||
{
|
||||
m_isInitializing = true;
|
||||
// Initialize Asset Bundler Batch
|
||||
ApplicationManager::Init();
|
||||
|
||||
AZ::IO::FixedMaxPath engineRoot = GetEngineRoot();
|
||||
|
||||
if (engineRoot.empty())
|
||||
{
|
||||
// Error has already been thrown
|
||||
return false;
|
||||
}
|
||||
|
||||
// Determine the name of the current project
|
||||
auto projectOutcome = AssetBundler::GetCurrentProjectName();
|
||||
if (!projectOutcome.IsSuccess())
|
||||
{
|
||||
AZ_Error("AssetBundler", false, projectOutcome.GetError().c_str());
|
||||
return false;
|
||||
}
|
||||
m_currentProjectName = projectOutcome.GetValue();
|
||||
|
||||
// Set up paths to the Project folder, Project Cache folder, and determine enabled platforms
|
||||
auto pathOutcome = InitializePaths();
|
||||
if (!pathOutcome.IsSuccess())
|
||||
{
|
||||
AZ_Error("AssetBundler", false, pathOutcome.GetError().c_str());
|
||||
return false;
|
||||
}
|
||||
|
||||
// Set up platform-specific Asset Catalogs
|
||||
m_platformCatalogManager = AZStd::make_unique<AzToolsFramework::PlatformAddressedAssetCatalogManager>();
|
||||
|
||||
// Define some application-level settings
|
||||
QApplication::setOrganizationName("Amazon");
|
||||
QApplication::setOrganizationDomain("amazon.com");
|
||||
QApplication::setApplicationName("Asset Bundler");
|
||||
|
||||
QLocale::setDefault(QLocale(QLocale::English, QLocale::UnitedStates));
|
||||
|
||||
QCoreApplication::setAttribute(Qt::AA_EnableHighDpiScaling);
|
||||
QCoreApplication::setAttribute(Qt::AA_UseHighDpiPixmaps);
|
||||
|
||||
m_isInitializing = false;
|
||||
|
||||
// Create the actual Qt Application
|
||||
m_qApp.reset(new QApplication(*GetArgC(), *GetArgV()));
|
||||
|
||||
// Create the Main Window
|
||||
m_mainWindow.reset(new MainWindow(this));
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool GUIApplicationManager::Run()
|
||||
{
|
||||
// Set up the Style Manager
|
||||
AzQtComponents::StyleManager styleManager(qApp);
|
||||
styleManager.initialize(qApp, GetEngineRoot());
|
||||
|
||||
AZ::IO::FixedMaxPath engineRoot(GetEngineRoot());
|
||||
QDir engineRootDir(engineRoot.c_str());
|
||||
AzQtComponents::StyleManager::addSearchPaths(
|
||||
QStringLiteral("style"),
|
||||
engineRootDir.filePath(QStringLiteral("Code/Tools/AssetBundler/source/ui/style")),
|
||||
QStringLiteral(":/AssetBundler/style"),
|
||||
engineRoot);
|
||||
AzQtComponents::StyleManager::setStyleSheet(m_mainWindow.data(), QStringLiteral("style:AssetBundler.qss"));
|
||||
|
||||
AzQtComponents::ConfigHelpers::loadConfig<Config, GUIApplicationManager>(&m_fileWatcher, &m_config, QStringLiteral("style:AssetBundlerConfig.ini"), this, std::bind(&GUIApplicationManager::ApplyConfig, this));
|
||||
ApplyConfig();
|
||||
|
||||
qApp->setWindowIcon(QIcon("style:AssetBundler-Icon-256x256@x2.ico"));
|
||||
|
||||
// Set up the Main Window
|
||||
auto wrapper = new AzQtComponents::WindowDecorationWrapper(Platform::GetWindowDecorationWrapperOption());
|
||||
wrapper->setGuest(m_mainWindow.data());
|
||||
m_mainWindow->Activate();
|
||||
wrapper->show();
|
||||
m_mainWindow->show();
|
||||
|
||||
qApp->setQuitOnLastWindowClosed(true);
|
||||
|
||||
// Run the application
|
||||
return qApp->exec();
|
||||
}
|
||||
|
||||
void GUIApplicationManager::AddWatchedPath(const QString& folderPath)
|
||||
{
|
||||
m_fileWatcher.addPath(folderPath);
|
||||
}
|
||||
|
||||
void GUIApplicationManager::AddWatchedPaths(const QSet<QString>& folderPaths)
|
||||
{
|
||||
m_fileWatcher.addPaths(folderPaths.values());
|
||||
}
|
||||
|
||||
void GUIApplicationManager::RemoveWatchedPath(const QString& path)
|
||||
{
|
||||
m_fileWatcher.removePath(path);
|
||||
}
|
||||
|
||||
void GUIApplicationManager::RemoveWatchedPaths(const QSet<QString>& paths)
|
||||
{
|
||||
// Check whether the list is empty to get rid of the warning from Qt
|
||||
if (paths.isEmpty())
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
m_fileWatcher.removePaths(paths.values());
|
||||
}
|
||||
|
||||
bool GUIApplicationManager::OnPreError(const char* /*window*/, const char* /*fileName*/, int /*line*/, const char* /*func*/, const char* message)
|
||||
{
|
||||
// We want to display errors during initialization, then let the MainWindow handle errors during runtime
|
||||
if (m_isInitializing)
|
||||
{
|
||||
// These are fatal initialization errors, and the application will shut down after the user closes the message box
|
||||
m_qApp.reset(new QApplication(*GetArgC(), *GetArgV()));
|
||||
QMessageBox errorMessageBox;
|
||||
errorMessageBox.setWindowTitle("Asset Bundler");
|
||||
errorMessageBox.setText(message);
|
||||
errorMessageBox.setStandardButtons(QMessageBox::Ok);
|
||||
errorMessageBox.setDefaultButton(QMessageBox::Ok);
|
||||
errorMessageBox.exec();
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
bool GUIApplicationManager::OnPreWarning(const char* /*window*/, const char* /*fileName*/, int /*line*/, const char* /*func*/, const char* /*message*/)
|
||||
{
|
||||
// Don't handle warnings, let the MainWindow print them
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
bool GUIApplicationManager::OnPrintf(const char* /*window*/, const char* /*message*/)
|
||||
{
|
||||
// This is disabled during initialization to prevent a lot of message spam printed to the CLI that gets generated on setup
|
||||
return m_isInitializing;
|
||||
}
|
||||
|
||||
AZ::Outcome<void, AZStd::string> GUIApplicationManager::InitializePaths()
|
||||
{
|
||||
// Calculate the path to the Cache for the current project
|
||||
auto pathOutcome = AssetBundler::GetProjectCacheFolderPath();
|
||||
if (!pathOutcome.IsSuccess())
|
||||
{
|
||||
return AZ::Failure(pathOutcome.GetError());
|
||||
}
|
||||
|
||||
m_currentProjectCacheFolder = pathOutcome.GetValue().String();
|
||||
|
||||
// Calculate the path to the current project folder
|
||||
pathOutcome = AssetBundler::GetProjectFolderPath();
|
||||
if (!pathOutcome.IsSuccess())
|
||||
{
|
||||
return AZ::Failure(pathOutcome.GetError());
|
||||
}
|
||||
|
||||
m_currentProjectFolder = pathOutcome.GetValue().String();
|
||||
|
||||
// Generate the AssetBundling folder inside the current project
|
||||
AzFramework::StringFunc::Path::ConstructFull(m_currentProjectFolder.c_str(), AssetBundlingFolderName, m_assetBundlingFolder);
|
||||
|
||||
// Seed Lists folder
|
||||
AzFramework::StringFunc::Path::ConstructFull(m_assetBundlingFolder.c_str(), SeedListsFolderName, m_seedListsFolder);
|
||||
AZ::Outcome<void, AZStd::string> createPathOutcome = AssetBundler::MakePath(m_seedListsFolder);
|
||||
if (!createPathOutcome.IsSuccess())
|
||||
{
|
||||
return createPathOutcome;
|
||||
}
|
||||
|
||||
// Asset Lists folder
|
||||
AzFramework::StringFunc::Path::ConstructFull(m_assetBundlingFolder.c_str(), AssetListsFolderName, m_assetListsFolder);
|
||||
createPathOutcome = AssetBundler::MakePath(m_assetListsFolder);
|
||||
if (!createPathOutcome.IsSuccess())
|
||||
{
|
||||
return createPathOutcome;
|
||||
}
|
||||
|
||||
// Rules folder
|
||||
AzFramework::StringFunc::Path::ConstructFull(m_assetBundlingFolder.c_str(), RulesFolderName, m_rulesFolder);
|
||||
createPathOutcome = AssetBundler::MakePath(m_rulesFolder);
|
||||
if (!createPathOutcome.IsSuccess())
|
||||
{
|
||||
return createPathOutcome;
|
||||
}
|
||||
|
||||
// Bundle Settings Folder
|
||||
AzFramework::StringFunc::Path::ConstructFull(m_assetBundlingFolder.c_str(), BundleSettingsFolderName, m_bundleSettingsFolder);
|
||||
createPathOutcome = AssetBundler::MakePath(m_bundleSettingsFolder);
|
||||
if (!createPathOutcome.IsSuccess())
|
||||
{
|
||||
return createPathOutcome;
|
||||
}
|
||||
|
||||
// Bundles Folder
|
||||
AzFramework::StringFunc::Path::ConstructFull(m_assetBundlingFolder.c_str(), BundlesFolderName, m_bundlesFolder);
|
||||
createPathOutcome = AssetBundler::MakePath(m_bundlesFolder);
|
||||
if (!createPathOutcome.IsSuccess())
|
||||
{
|
||||
return createPathOutcome;
|
||||
}
|
||||
|
||||
// Determine the enabled platforms
|
||||
const char* appRoot = nullptr;
|
||||
AzFramework::ApplicationRequests::Bus::BroadcastResult(appRoot, &AzFramework::ApplicationRequests::GetAppRoot);
|
||||
m_enabledPlatforms = GetEnabledPlatformFlags(GetEngineRoot(), appRoot, AZ::Utils::GetProjectPath().c_str());
|
||||
|
||||
// Determine which Gems are enabled for the current project
|
||||
if (!AzFramework::GetGemsInfo(m_gemInfoList, *m_settingsRegistry))
|
||||
{
|
||||
return AZ::Failure(AZStd::string::format("Failed to read Gems for project: %s\n", m_currentProjectName.c_str()));
|
||||
}
|
||||
|
||||
QObject::connect(&m_fileWatcher, &QFileSystemWatcher::directoryChanged, this, &GUIApplicationManager::DirectoryChanged);
|
||||
QObject::connect(&m_fileWatcher, &QFileSystemWatcher::fileChanged, this, &GUIApplicationManager::FileChanged);
|
||||
|
||||
return AZ::Success();
|
||||
}
|
||||
|
||||
void GUIApplicationManager::DirectoryChanged(const QString& directory)
|
||||
{
|
||||
UpdateTab(directory.toUtf8().data());
|
||||
}
|
||||
|
||||
void GUIApplicationManager::FileChanged(const QString& path)
|
||||
{
|
||||
// FileChanged will only be called when engine or gem seed files are updated
|
||||
// Otherwilse DirectoryChanged should be triggered
|
||||
AZStd::string extension;
|
||||
AzFramework::StringFunc::Path::GetExtension(path.toUtf8().data(), extension);
|
||||
extension = extension.starts_with(".") ? extension.substr(1) : extension;
|
||||
if (extension == AzToolsFramework::AssetSeedManager::GetSeedFileExtension())
|
||||
{
|
||||
UpdateTab(GetSeedListsFolder());
|
||||
}
|
||||
|
||||
// Many applications save an open file by writing a new file and then deleting the old one
|
||||
// Add the file path back if it has been removed from the watcher file list
|
||||
if (!m_fileWatcher.files().contains(path))
|
||||
{
|
||||
m_fileWatcher.addPath(path);
|
||||
}
|
||||
}
|
||||
|
||||
void GUIApplicationManager::ApplyConfig()
|
||||
{
|
||||
m_mainWindow->ApplyConfig();
|
||||
}
|
||||
|
||||
} // namespace AssetBundler
|
||||
|
||||
#include <source/utils/moc_GUIApplicationManager.cpp>
|
||||
@@ -0,0 +1,164 @@
|
||||
/*
|
||||
* 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.
|
||||
*
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#if !defined(Q_MOC_RUN)
|
||||
#include <source/utils/applicationManager.h>
|
||||
|
||||
#include <AzCore/Outcome/Outcome.h>
|
||||
#include <AzCore/std/containers/vector.h>
|
||||
|
||||
#include <AzFramework/Asset/AssetCatalog.h>
|
||||
#include <AzFramework/Platform/PlatformDefaults.h>
|
||||
|
||||
#include <QCoreApplication>
|
||||
#include <QDir>
|
||||
#include <QMap>
|
||||
#include <QSettings>
|
||||
#include <QSharedPointer>
|
||||
#include <QString>
|
||||
#include <QFileSystemWatcher>
|
||||
#endif
|
||||
|
||||
namespace AssetBundler
|
||||
{
|
||||
enum AssetBundlingFileType : int
|
||||
{
|
||||
SeedListFileType = 0,
|
||||
AssetListFileType,
|
||||
BundleSettingsFileType,
|
||||
BundleFileType,
|
||||
RulesFileType,
|
||||
NumBundlingFileTypes
|
||||
};
|
||||
|
||||
class MainWindow;
|
||||
|
||||
class GUIApplicationManager
|
||||
: public ApplicationManager
|
||||
{
|
||||
Q_OBJECT
|
||||
|
||||
public:
|
||||
|
||||
struct Config
|
||||
{
|
||||
// These default values are used if the values can't be read from AssetBundlerConfig.ini,
|
||||
// and the call to defaultConfig fails.
|
||||
|
||||
// Error Log
|
||||
int logTypeColumnWidth = -1;
|
||||
int logSourceColumnWidth = -1;
|
||||
|
||||
// General File Tables
|
||||
int fileTableWidth = -1;
|
||||
int fileNameColumnWidth = -1;
|
||||
|
||||
// Seeds Tab
|
||||
int checkBoxColumnWidth = -1;
|
||||
int seedListFileNameColumnWidth = -1;
|
||||
int projectNameColumnWidth = -1;
|
||||
int seedListContentsNameColumnWidth = -1;
|
||||
|
||||
// Asset Lists Tab
|
||||
int assetListFileNameColumnWidth = -1;
|
||||
int assetListPlatformColumnWidth = -1;
|
||||
int productAssetNameColumnWidth = -1;
|
||||
int productAssetRelativePathColumnWidth = -1;
|
||||
};
|
||||
|
||||
/*!
|
||||
* Loads the button config data from a settings object.
|
||||
*/
|
||||
static Config loadConfig(QSettings& settings);
|
||||
|
||||
/*!
|
||||
* Returns default button config data.
|
||||
*/
|
||||
static Config defaultConfig();
|
||||
|
||||
explicit GUIApplicationManager(int* argc, char*** argv, QObject* parent = 0);
|
||||
virtual ~GUIApplicationManager();
|
||||
|
||||
bool Init() override;
|
||||
|
||||
bool Run() override;
|
||||
|
||||
AZStd::string GetCurrentProjectFolder() { return m_currentProjectFolder; }
|
||||
AZStd::string GetAssetBundlingFolder() { return m_assetBundlingFolder; }
|
||||
AZStd::string GetSeedListsFolder() { return m_seedListsFolder; }
|
||||
AZStd::string GetAssetListsFolder() { return m_assetListsFolder; }
|
||||
AZStd::string GetRulesFolder() { return m_rulesFolder; }
|
||||
AZStd::string GetBundleSettingsFolder() { return m_bundleSettingsFolder; }
|
||||
AZStd::string GetBundlesFolder() { return m_bundlesFolder; }
|
||||
AZStd::string GetCurrentProjectCacheFolder() { return m_currentProjectCacheFolder; }
|
||||
|
||||
AzFramework::PlatformFlags GetEnabledPlatforms() { return m_enabledPlatforms; }
|
||||
|
||||
void AddWatchedPath(const QString& path);
|
||||
void AddWatchedPaths(const QSet<QString>& paths);
|
||||
void RemoveWatchedPath(const QString& path);
|
||||
void RemoveWatchedPaths(const QSet<QString>& paths);
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////////////////
|
||||
// Override the ApplicationManager TraceMessageBus methods so that messages go through MainWindow and not the CLI
|
||||
|
||||
bool OnPreError(const char* window, const char* /*fileName*/, int /*line*/, const char* /*func*/, const char* message) override;
|
||||
bool OnPreWarning(const char* /*window*/, const char* /*fileName*/, int /*line*/, const char* /*func*/, const char* /*message*/) override;
|
||||
bool OnPrintf(const char* /*window*/, const char* /*message*/) override;
|
||||
////////////////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
const Config& GetConfig() { return m_config; }
|
||||
|
||||
Q_SIGNALS:
|
||||
void ShowWindow();
|
||||
void UpdateTab(const AZStd::string& directory);
|
||||
void UpdateFiles(AssetBundlingFileType fileType, const AZStd::vector<AZStd::string>& absoluteFilePaths);
|
||||
|
||||
protected Q_SLOTS:
|
||||
void DirectoryChanged(const QString& directory);
|
||||
void FileChanged(const QString& path);
|
||||
void ApplyConfig();
|
||||
|
||||
private:
|
||||
/**
|
||||
* Generates directory information for all paths used in this tool
|
||||
* @return void on success, error message on failure
|
||||
*/
|
||||
AZ::Outcome<void, AZStd::string> InitializePaths();
|
||||
|
||||
QSharedPointer<QCoreApplication> m_qApp;
|
||||
|
||||
Config m_config;
|
||||
|
||||
QSharedPointer<MainWindow> m_mainWindow;
|
||||
|
||||
AZStd::string m_currentProjectFolder;
|
||||
AZStd::string m_assetBundlingFolder;
|
||||
AZStd::string m_seedListsFolder;
|
||||
AZStd::string m_assetListsFolder;
|
||||
AZStd::string m_rulesFolder;
|
||||
AZStd::string m_bundleSettingsFolder;
|
||||
AZStd::string m_bundlesFolder;
|
||||
AZStd::string m_currentProjectCacheFolder;
|
||||
|
||||
AzFramework::PlatformFlags m_enabledPlatforms = AzFramework::PlatformFlags::Platform_NONE;
|
||||
|
||||
AZStd::unique_ptr<AzToolsFramework::PlatformAddressedAssetCatalogManager> m_platformCatalogManager;
|
||||
|
||||
bool m_isInitializing = false;
|
||||
|
||||
QFileSystemWatcher m_fileWatcher;
|
||||
};
|
||||
|
||||
} // namespace AssetBundler
|
||||
@@ -45,8 +45,16 @@ namespace AssetBundler
|
||||
{
|
||||
const char compareVariablePrefix = '$';
|
||||
|
||||
ApplicationManager::ApplicationManager(int* argc, char*** argv)
|
||||
: AzToolsFramework::ToolsApplication(argc, argv)
|
||||
GemInfo::GemInfo(AZStd::string name, AZStd::string relativeFilePath, AZStd::string absoluteFilePath)
|
||||
: m_gemName(name)
|
||||
, m_relativeFilePath(relativeFilePath)
|
||||
, m_absoluteFilePath(absoluteFilePath)
|
||||
{
|
||||
}
|
||||
|
||||
ApplicationManager::ApplicationManager(int* argc, char*** argv, QObject* parent)
|
||||
: QObject(parent)
|
||||
, AzToolsFramework::ToolsApplication(argc, argv)
|
||||
{
|
||||
}
|
||||
|
||||
@@ -55,7 +63,7 @@ namespace AssetBundler
|
||||
DestroyApplication();
|
||||
}
|
||||
|
||||
void ApplicationManager::Init()
|
||||
bool ApplicationManager::Init()
|
||||
{
|
||||
AZ::Debug::TraceMessageBus::Handler::BusConnect();
|
||||
Start(AzFramework::Application::Descriptor());
|
||||
@@ -72,8 +80,11 @@ namespace AssetBundler
|
||||
m_assetSeedManager = AZStd::make_unique<AzToolsFramework::AssetSeedManager>();
|
||||
AZ_TracePrintf(AssetBundler::AppWindowName, "\n");
|
||||
|
||||
g_cachedEngineRoot = AZ::IO::FixedMaxPath(GetEngineRoot());
|
||||
|
||||
// There is no need to update the UserSettings file, so we can avoid a race condition by disabling save on shutdown
|
||||
AZ::UserSettingsComponentRequestBus::Broadcast(&AZ::UserSettingsComponentRequests::DisableSaveOnFinalize);
|
||||
return true;
|
||||
}
|
||||
|
||||
void ApplicationManager::DestroyApplication()
|
||||
@@ -1522,7 +1533,7 @@ namespace AssetBundler
|
||||
}
|
||||
}
|
||||
|
||||
AZStd::vector<AZStd::string> defaultSeeds = GetDefaultSeeds(GetEngineRoot(), AZ::Utils::GetProjectPath(), m_currentProjectName);
|
||||
AZStd::vector<AZStd::string> defaultSeeds = GetDefaultSeeds(AZ::Utils::GetProjectPath(), m_currentProjectName);
|
||||
if (defaultSeeds.empty())
|
||||
{
|
||||
// Error has already been thrown
|
||||
@@ -2847,3 +2858,4 @@ namespace AssetBundler
|
||||
return !m_showVerboseOutput;
|
||||
}
|
||||
} // namespace AssetBundler
|
||||
#include <source/utils/moc_applicationManager.cpp>
|
||||
|
||||
@@ -11,6 +11,7 @@
|
||||
*/
|
||||
#pragma once
|
||||
|
||||
#if !defined(Q_MOC_RUN)
|
||||
#include <AzToolsFramework/Application/ToolsApplication.h>
|
||||
#include <AzToolsFramework/Asset/AssetSeedManager.h>
|
||||
#include <AzToolsFramework/Asset/AssetBundler.h>
|
||||
@@ -22,7 +23,7 @@
|
||||
#include <AzToolsFramework/API/EditorAssetSystemAPI.h>
|
||||
#include <source/utils/utils.h>
|
||||
#include <AzToolsFramework/AssetCatalog/PlatformAddressedAssetCatalogManager.h>
|
||||
|
||||
#endif
|
||||
namespace AssetBundler
|
||||
{
|
||||
struct SeedsParams
|
||||
@@ -161,16 +162,18 @@ namespace AssetBundler
|
||||
};
|
||||
|
||||
class ApplicationManager
|
||||
: public AZ::Debug::TraceMessageBus::Handler
|
||||
: public QObject
|
||||
, public AZ::Debug::TraceMessageBus::Handler
|
||||
, public AzToolsFramework::ToolsApplication
|
||||
{
|
||||
Q_OBJECT
|
||||
public:
|
||||
explicit ApplicationManager(int* argc, char*** argv);
|
||||
~ApplicationManager();
|
||||
explicit ApplicationManager(int* argc, char*** argv, QObject* parent = 0);
|
||||
virtual ~ApplicationManager();
|
||||
|
||||
void Init();
|
||||
virtual bool Init();
|
||||
void DestroyApplication();
|
||||
bool Run();
|
||||
virtual bool Run();
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////////////////
|
||||
// AzFramework::Application overrides
|
||||
|
||||
@@ -31,6 +31,7 @@ AZ_PUSH_DISABLE_WARNING(4244 4251, "-Wunknown-warning-option")
|
||||
#include <QDir>
|
||||
#include <QString>
|
||||
#include <QStringList>
|
||||
#include <QJsonDocument>
|
||||
AZ_POP_DISABLE_WARNING
|
||||
|
||||
namespace AssetBundler
|
||||
@@ -108,6 +109,8 @@ namespace AssetBundler
|
||||
|
||||
const char* AssetCatalogFilename = "assetcatalog.xml";
|
||||
|
||||
AZ::IO::FixedMaxPath g_cachedEngineRoot;
|
||||
|
||||
|
||||
const char EngineDirectoryName[] = "Engine";
|
||||
const char RestrictedDirectoryName[] = "restricted";
|
||||
@@ -128,7 +131,7 @@ namespace AssetBundler
|
||||
AZStd::unordered_map<AZStd::string, AZStd::string>& defaultSeedLists,
|
||||
AzFramework::PlatformFlags platformFlags)
|
||||
{
|
||||
AZ::IO::FixedMaxPath engineRoot(GetEngineRoot());
|
||||
AZ::IO::FixedMaxPath engineRoot(GetCachedEngineRoot());
|
||||
AZ::IO::FixedMaxPath engineRestrictedRoot = engineRoot / RestrictedDirectoryName;
|
||||
|
||||
AZ::IO::FixedMaxPath engineLocalPath = AZ::IO::PathView(engineDirectory.LexicallyRelative(engineRoot));
|
||||
@@ -201,15 +204,10 @@ namespace AssetBundler
|
||||
}
|
||||
}
|
||||
|
||||
AZ::IO::FixedMaxPath GetEngineRoot()
|
||||
AZ::IO::FixedMaxPath GetCachedEngineRoot()
|
||||
{
|
||||
AZ::IO::FixedMaxPath engineRootPath;
|
||||
if (auto settingsRegistry = AZ::SettingsRegistry::Get(); settingsRegistry != nullptr)
|
||||
{
|
||||
settingsRegistry->Get(engineRootPath.Native(), AZ::SettingsRegistryMergeUtils::FilePathKey_EngineRootFolder);
|
||||
}
|
||||
|
||||
return engineRootPath;
|
||||
AZ_Error(AppWindowName, !g_cachedEngineRoot.empty(), "Cached Engine Root has not been initialized by the Bundler.");
|
||||
return g_cachedEngineRoot;
|
||||
}
|
||||
|
||||
void AddPlatformIdentifier(AZStd::string& filePath, const AZStd::string& platformIdentifier)
|
||||
@@ -276,11 +274,11 @@ namespace AssetBundler
|
||||
return defaultSeedLists;
|
||||
}
|
||||
|
||||
AZStd::vector<AZStd::string> GetDefaultSeeds(AZStd::string_view enginePath, AZStd::string_view projectPath, AZStd::string_view projectName)
|
||||
AZStd::vector<AZStd::string> GetDefaultSeeds(AZStd::string_view projectPath, AZStd::string_view projectName)
|
||||
{
|
||||
AZStd::vector<AZStd::string> defaultSeeds;
|
||||
|
||||
defaultSeeds.emplace_back(GetProjectDependenciesAssetPath(enginePath, projectPath, projectName));
|
||||
defaultSeeds.emplace_back(GetProjectDependenciesAssetPath(projectPath, projectName));
|
||||
|
||||
return defaultSeeds;
|
||||
}
|
||||
@@ -294,34 +292,12 @@ namespace AssetBundler
|
||||
return projectDependenciesFilePath.LexicallyNormal();
|
||||
}
|
||||
|
||||
AZ::IO::Path GetProjectDependenciesFileTemplate(AZStd::string_view engineRoot)
|
||||
{
|
||||
AZ::IO::Path projectDependenciesFileTemplate = engineRoot;
|
||||
projectDependenciesFileTemplate /= DefaultProjectTemplatePath;
|
||||
projectDependenciesFileTemplate /= AZStd::string::format("%s%s", ProjectName, DependenciesFileSuffix);
|
||||
projectDependenciesFileTemplate.ReplaceExtension(DependenciesFileExtension);
|
||||
return projectDependenciesFileTemplate.LexicallyNormal();
|
||||
}
|
||||
|
||||
AZ::IO::Path GetProjectDependenciesAssetPath(AZStd::string_view enginePath, AZStd::string_view projectPath, AZStd::string_view projectName)
|
||||
AZ::IO::Path GetProjectDependenciesAssetPath(AZStd::string_view projectPath, AZStd::string_view projectName)
|
||||
{
|
||||
AZ::IO::Path projectDependenciesFile = GetProjectDependenciesFile(projectPath, projectName);
|
||||
if (!AZ::IO::FileIOBase::GetInstance()->Exists(projectDependenciesFile.c_str()))
|
||||
{
|
||||
AZ_TracePrintf(AssetBundler::AppWindowName, "Project dependencies file %s doesn't exist.\n", projectDependenciesFile.c_str());
|
||||
|
||||
AZ::IO::Path projectDependenciesFileTemplate = GetProjectDependenciesFileTemplate(enginePath);
|
||||
if (AZ::IO::FileIOBase::GetInstance()->Copy(projectDependenciesFileTemplate.c_str(), projectDependenciesFile.c_str()))
|
||||
{
|
||||
AZ_TracePrintf(AssetBundler::AppWindowName, "Copied project dependencies file template %s to the current project.\n",
|
||||
projectDependenciesFile.c_str());
|
||||
}
|
||||
else
|
||||
{
|
||||
AZ_Error(AppWindowName, false, "Failed to copy project dependencies file template %s from default project"
|
||||
" template to the current project.\n", projectDependenciesFileTemplate.c_str());
|
||||
return {};
|
||||
}
|
||||
AZ_Error(AssetBundler::AppWindowName, false, "Project dependencies file %s doesn't exist.\n", projectDependenciesFile.c_str());
|
||||
}
|
||||
|
||||
// Turn the absolute path into a cache-relative path
|
||||
@@ -538,6 +514,14 @@ namespace AssetBundler
|
||||
return platformSpecificCacheFolderPath;
|
||||
}
|
||||
|
||||
AZStd::string GenerateKeyFromAbsolutePath(const AZStd::string& absoluteFilePath)
|
||||
{
|
||||
AZStd::string key(absoluteFilePath);
|
||||
AzFramework::StringFunc::Path::Normalize(key);
|
||||
AzFramework::StringFunc::Path::StripDrive(key);
|
||||
return key;
|
||||
}
|
||||
|
||||
void ConvertToRelativePath(AZStd::string_view parentFolderPath, AZStd::string& absoluteFilePath)
|
||||
{
|
||||
absoluteFilePath = AZ::IO::PathView(absoluteFilePath).LexicallyRelative(parentFolderPath).String();
|
||||
@@ -822,4 +806,26 @@ namespace AssetBundler
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
QJsonObject ReadJson(const AZStd::string& filePath)
|
||||
{
|
||||
QByteArray byteArray;
|
||||
QFile jsonFile;
|
||||
jsonFile.setFileName(filePath.c_str());
|
||||
jsonFile.open(QIODevice::ReadOnly | QIODevice::Text);
|
||||
byteArray = jsonFile.readAll();
|
||||
jsonFile.close();
|
||||
|
||||
return QJsonDocument::fromJson(byteArray).object();
|
||||
}
|
||||
|
||||
void SaveJson(const AZStd::string& filePath, const QJsonObject& jsonObject)
|
||||
{
|
||||
QFile jsonFile(filePath.c_str());
|
||||
QJsonDocument JsonDocument;
|
||||
JsonDocument.setObject(jsonObject);
|
||||
jsonFile.open(QFile::WriteOnly | QFile::Text | QFile::Truncate);
|
||||
jsonFile.write(JsonDocument.toJson());
|
||||
jsonFile.close();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -19,7 +19,9 @@
|
||||
#include <AzFramework/Platform/PlatformDefaults.h>
|
||||
#include <AzToolsFramework/Asset/AssetBundler.h>
|
||||
#include <AzToolsFramework/Asset/AssetUtils.h>
|
||||
|
||||
#include <QDir>
|
||||
#include <QStringList>
|
||||
#include <QJsonObject>
|
||||
|
||||
namespace AssetBundler
|
||||
{
|
||||
@@ -120,8 +122,20 @@ namespace AssetBundler
|
||||
////////////////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
extern const char* AssetCatalogFilename;
|
||||
extern AZ::IO::FixedMaxPath g_cachedEngineRoot;
|
||||
static const size_t MaxErrorMessageLength = 4096;
|
||||
|
||||
//! This struct stores gem related information
|
||||
struct GemInfo
|
||||
{
|
||||
AZ_CLASS_ALLOCATOR(GemInfo, AZ::SystemAllocator, 0);
|
||||
GemInfo(AZStd::string name, AZStd::string relativeFilePath, AZStd::string absoluteFilePath);
|
||||
GemInfo() = default;
|
||||
AZStd::string m_gemName;
|
||||
AZStd::string m_relativeFilePath;
|
||||
AZStd::string m_absoluteFilePath;
|
||||
};
|
||||
|
||||
|
||||
// The Warning Absorber is used to absorb warnings
|
||||
// One case that this is being used is during loading of the asset catalog.
|
||||
@@ -137,8 +151,8 @@ namespace AssetBundler
|
||||
bool OnPreWarning(const char* window, const char* fileName, int line, const char* func, const char* message) override;
|
||||
};
|
||||
|
||||
// Returns the engine root
|
||||
AZ::IO::FixedMaxPath GetEngineRoot();
|
||||
// Returns the cached engine root. Throws an error if the cached path has not been initialized by the Bundler Application.
|
||||
AZ::IO::FixedMaxPath GetCachedEngineRoot();
|
||||
|
||||
/**
|
||||
* Determines the name of the currently enabled game project
|
||||
@@ -192,6 +206,8 @@ namespace AssetBundler
|
||||
*/
|
||||
AZ::IO::Path GetPlatformSpecificCacheFolderPath();
|
||||
|
||||
AZStd::string GenerateKeyFromAbsolutePath(const AZStd::string& absoluteFilePath);
|
||||
|
||||
void ConvertToRelativePath(AZStd::string_view parentFolderPath, AZStd::string& absoluteFilePath);
|
||||
|
||||
AZ::Outcome<void, AZStd::string> MakePath(const AZStd::string& path);
|
||||
@@ -207,16 +223,13 @@ namespace AssetBundler
|
||||
const AZStd::vector<AzFramework::GemInfo>& gemInfoList, AzFramework::PlatformFlags platformFlags);
|
||||
|
||||
//! Returns a vector of relative paths to Assets that should be included as default Seeds, but are not already in a Seed List file.
|
||||
AZStd::vector<AZStd::string> GetDefaultSeeds(AZStd::string_view enginePath, AZStd::string_view projectPath, AZStd::string_view projectName);
|
||||
AZStd::vector<AZStd::string> GetDefaultSeeds(AZStd::string_view projectPath, AZStd::string_view projectName);
|
||||
|
||||
//! Returns the absolute path of {ProjectName}_Dependencies.xml
|
||||
AZ::IO::Path GetProjectDependenciesFile(AZStd::string_view productPath, AZStd::string_view projectName);
|
||||
|
||||
//! Returns the absolute path of the project dependencies file in the default project template
|
||||
AZ::IO::Path GetProjectDependenciesFileTemplate(AZStd::string_view enginePath);
|
||||
|
||||
//! Creates the ProjectName_Dependencies.xml file if it does not exist, and adds returns the relative path to the asset in the Cache.
|
||||
AZ::IO::Path GetProjectDependenciesAssetPath(AZStd::string_view enginePath, AZStd::string_view projectPath, AZStd::string_view projectName);
|
||||
AZ::IO::Path GetProjectDependenciesAssetPath(AZStd::string_view projectPath, AZStd::string_view projectName);
|
||||
|
||||
//! Returns the map from gem seed list file path to gem name
|
||||
AZStd::unordered_map<AZStd::string, AZStd::string> GetGemSeedListFilePathToGemNameMap(const AZStd::vector<AzFramework::GemInfo>& gemInfoList, AzFramework::PlatformFlags platformFlags);
|
||||
@@ -229,6 +242,9 @@ namespace AssetBundler
|
||||
//! Please note that the game project could be in a different location to the engine therefore we need the assetRoot param.
|
||||
AzFramework::PlatformFlags GetEnabledPlatformFlags(AZStd::string_view enginePath, AZStd::string_view assetRoot, AZStd::string_view projectPath);
|
||||
|
||||
QJsonObject ReadJson(const AZStd::string& filePath);
|
||||
void SaveJson(const AZStd::string& filePath, const QJsonObject& jsonObject);
|
||||
|
||||
//! Filepath is a helper class that is used to find the absolute path of a file
|
||||
//! if the inputted file path is an absolute path than it does nothing
|
||||
//! if the inputted file path is a relative path than based on whether the user
|
||||
|
||||
@@ -113,14 +113,13 @@ namespace AssetBundler
|
||||
AZ::SettingsRegistry::Register(&m_registry);
|
||||
}
|
||||
|
||||
const char* engineRoot = nullptr;
|
||||
AzFramework::ApplicationRequests::Bus::BroadcastResult(engineRoot, &AzFramework::ApplicationRequests::GetEngineRoot);
|
||||
if (!engineRoot)
|
||||
AssetBundler::g_cachedEngineRoot = m_data->m_application.get()->GetEngineRoot();
|
||||
if (AssetBundler::g_cachedEngineRoot.empty())
|
||||
{
|
||||
GTEST_FATAL_FAILURE_(AZStd::string::format("Unable to locate engine root.\n").c_str());
|
||||
}
|
||||
|
||||
AzFramework::StringFunc::Path::Join(engineRoot, RelativeTestFolder, m_data->m_testEngineRoot);
|
||||
AzFramework::StringFunc::Path::Join(AssetBundler::g_cachedEngineRoot.c_str(), RelativeTestFolder, m_data->m_testEngineRoot);
|
||||
|
||||
m_data->m_localFileIO = aznew AZ::IO::LocalFileIO();
|
||||
m_data->m_priorFileIO = AZ::IO::FileIOBase::GetInstance();
|
||||
|
||||
Reference in New Issue
Block a user