You've already forked UnrealEngineUWP
mirror of
https://github.com/izzy2lost/UnrealEngineUWP.git
synced 2026-03-26 18:15:20 -07:00
This change consists of multiple changes: Core: - Deprecation of ANY_PACKAGE macro. Added ANY_PACKAGE_DEPRECATED macro which can still be used for backwards compatibility purposes (only used in CoreUObject) - Deprecation of StaticFindObjectFast* functions that take bAnyPackage parameter - Added UStruct::GetStructPathName function that returns FTopLevelAssetPath representing the path name (package + object FName, super quick compared to UObject::GetPathName) + wrapper UClass::GetClassPathName to make it look better when used with UClasses - Added (Static)FindFirstObject* functions that find a first object given its Name (no Outer). These functions are used in places I consider valid to do global UObject (UClass) lookups like parsing command line parameters / checking for unique object names - Added static UClass::TryFindType function which serves a similar purpose as FindFirstObject however it's going to throw a warning (with a callstack / maybe ensure in the future?) if short class name is provided. This function is used in places that used to use short class names but now should have been converted to use path names to catch any potential regressions and or edge cases I missed. - Added static UClass::TryConvertShortNameToPathName utility function - Added static UClass::TryFixShortClassNameExportPath utility function - Object text export paths will now also include class path (Texture2D'/Game/Textures/Grass.Grass' -> /Script/Engine.Texture2D'/Game/Textures/Grass.Grass') - All places that manually generated object export paths for objects will now use FObjectPropertyBase::GetExportPath - Added a new startup test that checks for short type names in UClass/FProperty MetaData values AssetRegistry: - Deprecated any member variables (FAssetData / FARFilter) or functions that use FNames to represent class names and replaced them with FTopLevelAssetPath - Added new member variables and new function overloads that use FTopLevelAssetPath to represent class names - This also applies to a few other modules' APIs to match AssetRegistry changes Everything else: - Updated code that used ANY_PACKAGE (depending on the use case) to use FindObject(nullptr, PathToObject), UClass::TryFindType (used when path name is expected, warns if it's a short name) or FindFirstObject (usually for finding types based on user input but there's been a few legitimate use cases not related to user input) - Updated code that used AssetRegistry API to use FTopLevelAssetPaths and USomeClass::StaticClass()->GetClassPathName() instead of GetFName() - Updated meta data and hardcoded FindObject(ANY_PACKAGE, "EEnumNameOrClassName") calls to use path names #jira UE-99463 #rb many.people [FYI] Marcus.Wassmer #preflight 629248ec2256738f75de9b32 #codereviewnumbers 20320742, 20320791, 20320799, 20320756, 20320809, 20320830, 20320840, 20320846, 20320851, 20320863, 20320780, 20320765, 20320876, 20320786 #ROBOMERGE-OWNER: robert.manuszewski #ROBOMERGE-AUTHOR: robert.manuszewski #ROBOMERGE-SOURCE: CL 20430220 via CL 20433854 via CL 20435474 via CL 20435484 #ROBOMERGE-BOT: UE5 (Release-Engine-Staging -> Main) (v949-20362246) [CL 20448496 by robert manuszewski in ue5-main branch]
988 lines
29 KiB
C++
988 lines
29 KiB
C++
// Copyright Epic Games, Inc. All Rights Reserved.
|
|
|
|
#include "Dialogs/SDeleteAssetsDialog.h"
|
|
#include "Framework/Commands/UIAction.h"
|
|
#include "Framework/Commands/UICommandList.h"
|
|
#include "Widgets/Notifications/SProgressBar.h"
|
|
#include "Widgets/Text/STextBlock.h"
|
|
#include "Framework/MultiBox/MultiBoxBuilder.h"
|
|
#include "Widgets/Input/SButton.h"
|
|
#include "Widgets/Input/SComboButton.h"
|
|
#include "Widgets/Views/SListView.h"
|
|
#include "Widgets/Input/SCheckBox.h"
|
|
#include "Styling/AppStyle.h"
|
|
#include "Settings/EditorLoadingSavingSettings.h"
|
|
#include "EditorDirectories.h"
|
|
#include "FileHelpers.h"
|
|
#include "Misc/MessageDialog.h"
|
|
#include "IContentBrowserSingleton.h"
|
|
#include "ContentBrowserModule.h"
|
|
#include "Editor.h"
|
|
|
|
#include "Framework/Commands/GenericCommands.h"
|
|
#include "Subsystems/AssetEditorSubsystem.h"
|
|
|
|
#define LOCTEXT_NAMESPACE "SDeleteAssetsDialog"
|
|
|
|
namespace DeleteAssetsView
|
|
{
|
|
/** IDs for list columns */
|
|
static const FName ColumnID_Asset( "Asset" );
|
|
static const FName ColumnID_AssetClass( "Class" );
|
|
static const FName ColumnID_DiskReferences( "DiskReferences" );
|
|
static const FName ColumnID_MemoryReferences( "MemoryReferences" );
|
|
}
|
|
|
|
static FLinearColor DangerColor( 0.715465432, 0.034230207, 0 );
|
|
static FLinearColor WarningColor( 1, 1, 0 );
|
|
|
|
|
|
//////////////////////////////////////////////////////////////////////////
|
|
// SPendingDeleteRow
|
|
|
|
class SPendingDeleteRow : public SMultiColumnTableRow< TSharedPtr<FPendingDelete> >
|
|
{
|
|
public:
|
|
|
|
SLATE_BEGIN_ARGS( SPendingDeleteRow ) { }
|
|
SLATE_END_ARGS()
|
|
|
|
void Construct( const FArguments& InArgs, const TSharedRef<STableViewBase>& InOwnerTableView, TSharedPtr<FPendingDelete> InItem )
|
|
{
|
|
Item = InItem;
|
|
|
|
SMultiColumnTableRow< TSharedPtr<FPendingDelete> >::Construct(FSuperRowType::FArguments(), InOwnerTableView);
|
|
}
|
|
|
|
virtual TSharedRef<SWidget> GenerateWidgetForColumn( const FName& ColumnName )
|
|
{
|
|
if ( ColumnName == DeleteAssetsView::ColumnID_Asset )
|
|
{
|
|
return SNew( SHorizontalBox )
|
|
+ SHorizontalBox::Slot()
|
|
.AutoWidth()
|
|
.Padding( 3, 0, 0, 0 )
|
|
[
|
|
SNew( STextBlock )
|
|
.Text(FText::FromString(Item->GetObject()->GetName()))
|
|
];
|
|
}
|
|
else if ( ColumnName == DeleteAssetsView::ColumnID_AssetClass )
|
|
{
|
|
return SNew( STextBlock )
|
|
.Text(FText::FromString(Item->GetObject()->GetClass()->GetName()));
|
|
}
|
|
else if ( ColumnName == DeleteAssetsView::ColumnID_DiskReferences )
|
|
{
|
|
FFormatNamedArguments Args;
|
|
Args.Add( TEXT( "AssetCount" ), FText::AsNumber( Item->RemainingDiskReferences ) );
|
|
|
|
FText OnDiskCountText = Item->RemainingDiskReferences > 1 ? FText::Format( LOCTEXT( "OnDiskAssetReferences", "{AssetCount} References" ), Args ) : FText::Format( LOCTEXT( "OnDiskAssetReference", "{AssetCount} Reference" ), Args );
|
|
|
|
return SNew( STextBlock )
|
|
.Text( OnDiskCountText )
|
|
.Visibility( Item->RemainingDiskReferences > 0 ? EVisibility::Visible : EVisibility::Hidden );
|
|
}
|
|
else if ( ColumnName == DeleteAssetsView::ColumnID_MemoryReferences )
|
|
{
|
|
FFormatNamedArguments Args;
|
|
Args.Add( TEXT( "ReferenceCount" ), FText::AsNumber( Item->RemainingMemoryReferences ) );
|
|
|
|
FText InMemoryCountText = Item->RemainingMemoryReferences > 1 ? FText::Format( LOCTEXT( "InMemoryReferences", "{ReferenceCount} References" ), Args ) : FText::Format( LOCTEXT( "OnDiskReference", "{ReferenceCount} Reference" ), Args );
|
|
|
|
return SNew( STextBlock )
|
|
.Text( InMemoryCountText )
|
|
.Visibility( Item->RemainingMemoryReferences > 0 ? EVisibility::Visible : EVisibility::Hidden );
|
|
}
|
|
|
|
return SNullWidget::NullWidget;
|
|
}
|
|
|
|
private:
|
|
TSharedPtr<FPendingDelete> Item;
|
|
};
|
|
|
|
//////////////////////////////////////////////////////////////////////////
|
|
// SDeleteAssetsDialog
|
|
|
|
SDeleteAssetsDialog::~SDeleteAssetsDialog()
|
|
{
|
|
DeleteModel->OnStateChanged().RemoveAll( this );
|
|
}
|
|
|
|
void SDeleteAssetsDialog::Construct( const FArguments& InArgs, TSharedRef<FAssetDeleteModel> InDeleteModel )
|
|
{
|
|
//bIsActiveTimerRegistered = false;
|
|
bIsActiveTimerRegistered = true;
|
|
RegisterActiveTimer( 0.f, FWidgetActiveTimerDelegate::CreateSP( this, &SDeleteAssetsDialog::TickDeleteModel ) );
|
|
|
|
DeleteModel = InDeleteModel;
|
|
|
|
// Save off the attributes
|
|
ParentWindow = InArgs._ParentWindow;
|
|
|
|
ReferencerCommands = TSharedPtr< FUICommandList >(new FUICommandList);
|
|
|
|
ReferencerCommands->MapAction(FGenericCommands::Get().Delete, FUIAction(
|
|
FExecuteAction::CreateSP( this, &SDeleteAssetsDialog::ExecuteDeleteReferencers ),
|
|
FCanExecuteAction::CreateSP( this, &SDeleteAssetsDialog::CanExecuteDeleteReferencers )
|
|
) );
|
|
|
|
// Create the widgets
|
|
ChildSlot
|
|
[
|
|
SAssignNew(RootContainer, SBorder)
|
|
.BorderImage( FAppStyle::GetBrush( "AssetDeleteDialog.Background" ) )
|
|
.Padding(10)
|
|
];
|
|
|
|
DeleteModel->OnStateChanged().AddRaw(this, &SDeleteAssetsDialog::HandleDeleteModelStateChanged);
|
|
|
|
// Manually fire the state changed event so that we are setup for the initial state.
|
|
HandleDeleteModelStateChanged(DeleteModel->GetState());
|
|
}
|
|
|
|
TSharedRef<SWidget> SDeleteAssetsDialog::BuildProgressDialog()
|
|
{
|
|
return SNew( SVerticalBox )
|
|
|
|
// Show Progress Text
|
|
+ SVerticalBox::Slot()
|
|
.VAlign(VAlign_Center)
|
|
.FillHeight( 1.0f )
|
|
[
|
|
SNew( SVerticalBox )
|
|
|
|
+ SVerticalBox::Slot()
|
|
.Padding( 5.0f, 0 )
|
|
[
|
|
SNew( STextBlock )
|
|
.Text( this, &SDeleteAssetsDialog::ScanningText )
|
|
]
|
|
|
|
// Show Progress
|
|
+ SVerticalBox::Slot()
|
|
.AutoHeight()
|
|
.Padding( 5.0f, 10.0f )
|
|
[
|
|
SNew( SProgressBar )
|
|
.Percent( this, &SDeleteAssetsDialog::ScanningProgressFraction )
|
|
]
|
|
];
|
|
}
|
|
|
|
TSharedRef<SWidget> SDeleteAssetsDialog::BuildDeleteDialog()
|
|
{
|
|
const auto* LoadingSavingSettings = GetDefault<UEditorLoadingSavingSettings>();
|
|
|
|
FFormatNamedArguments Args;
|
|
Args.Add( TEXT( "OnDiskReferences" ), FText::AsNumber( DeleteModel->GetAssetReferences().Num() ) );
|
|
|
|
TSharedRef< SHeaderRow > HeaderRowWidget =
|
|
SNew( SHeaderRow )
|
|
+ SHeaderRow::Column( DeleteAssetsView::ColumnID_Asset )
|
|
.DefaultLabel( LOCTEXT( "Column_AssetName", "Asset" ) )
|
|
.HAlignHeader( EHorizontalAlignment::HAlign_Left )
|
|
.FillWidth(0.5f)
|
|
+ SHeaderRow::Column( DeleteAssetsView::ColumnID_AssetClass )
|
|
.DefaultLabel( LOCTEXT( "Column_AssetClass", "Class" ) )
|
|
.HAlignHeader( EHorizontalAlignment::HAlign_Left )
|
|
.FillWidth( 0.25f )
|
|
+ SHeaderRow::Column( DeleteAssetsView::ColumnID_DiskReferences )
|
|
.DefaultLabel( LOCTEXT( "Column_DiskReferences", "Asset Referencers" ) )
|
|
.HAlignHeader( EHorizontalAlignment::HAlign_Left )
|
|
.FillWidth( 0.25f )
|
|
+ SHeaderRow::Column( DeleteAssetsView::ColumnID_MemoryReferences )
|
|
.DefaultLabel( LOCTEXT( "Column_MemoryReferences", "Memory References" ) )
|
|
.HAlignHeader( EHorizontalAlignment::HAlign_Left )
|
|
.FillWidth( 0.25f );
|
|
|
|
return SNew( SVerticalBox )
|
|
|
|
// The to be deleted assets
|
|
+ SVerticalBox::Slot()
|
|
.FillHeight( 0.5f )
|
|
.Padding( 5.0f )
|
|
[
|
|
SNew( SBorder )
|
|
.BorderImage( FAppStyle::GetBrush( "ToolPanel.GroupBorder" ) )
|
|
.Padding( FMargin(0, 0, 0, 3) )
|
|
[
|
|
SNew( SVerticalBox )
|
|
|
|
// Attempting delete text
|
|
+ SVerticalBox::Slot()
|
|
.AutoHeight()
|
|
[
|
|
SNew( SBorder )
|
|
.BorderImage( FAppStyle::GetBrush( "DetailsView.CategoryTop" ) )
|
|
.BorderBackgroundColor( FLinearColor( .6, .6, .6, 1.0f ) )
|
|
.Padding(3.0f)
|
|
[
|
|
SNew( STextBlock )
|
|
.Text( LOCTEXT( "AttemptingDelete", "Pending Deleted Assets" ) )
|
|
.Font( FAppStyle::GetFontStyle( "BoldFont" ) )
|
|
.ShadowOffset( FVector2D( 1.0f, 1.0f ) )
|
|
]
|
|
]
|
|
|
|
+ SVerticalBox::Slot()
|
|
.FillHeight(1.0f)
|
|
[
|
|
SAssignNew( ObjectsToDeleteList, SListView< TSharedPtr<FPendingDelete> > )
|
|
.ListItemsSource( DeleteModel->GetPendingDeletedAssets() )
|
|
.OnGenerateRow( this, &SDeleteAssetsDialog::HandleGenerateAssetRow )
|
|
.HeaderRow( HeaderRowWidget )
|
|
]
|
|
]
|
|
]
|
|
|
|
+ SVerticalBox::Slot()
|
|
.AutoHeight()
|
|
.Padding( 5.0f )
|
|
[
|
|
SNew( SBorder )
|
|
.BorderBackgroundColor( FLinearColor::Red )
|
|
.BorderImage( FAppStyle::GetBrush( "ToolPanel.GroupBorder" ) )
|
|
.Visibility( this, &SDeleteAssetsDialog::GetReferencesVisiblity )
|
|
.Padding(5.0f)
|
|
[
|
|
SNew( STextBlock )
|
|
.Text( LOCTEXT( "References", "Some of the assets being deleted are still referenced in memory." ) )
|
|
]
|
|
]
|
|
|
|
+ SVerticalBox::Slot()
|
|
.AutoHeight()
|
|
.Padding( 5.0f )
|
|
[
|
|
SNew( SBorder )
|
|
.BorderBackgroundColor( FLinearColor::Yellow )
|
|
.BorderImage( FAppStyle::GetBrush( "ToolPanel.GroupBorder" ) )
|
|
.Visibility( this, &SDeleteAssetsDialog::GetUndoVisiblity )
|
|
.Padding( 5.0f )
|
|
[
|
|
SNew( STextBlock )
|
|
.Text( LOCTEXT( "DeleteUndo", "There are references in the undo history, so the undo history will be cleared." ) )
|
|
]
|
|
]
|
|
|
|
+ SVerticalBox::Slot()
|
|
.FillHeight( 1.0f )
|
|
.Padding( 5.0f )
|
|
[
|
|
SNew( SBorder )
|
|
.BorderImage( FAppStyle::GetBrush( "ToolPanel.GroupBorder" ) )
|
|
.Padding( FMargin( 0, 0, 0, 3 ) )
|
|
.Visibility( this, &SDeleteAssetsDialog::GetAssetReferencesVisiblity)
|
|
[
|
|
SNew( SVerticalBox )
|
|
|
|
// Pending Deletes
|
|
+ SVerticalBox::Slot()
|
|
.AutoHeight()
|
|
[
|
|
SNew( SBorder )
|
|
.BorderImage( FAppStyle::GetBrush( "DetailsView.CategoryTop" ) )
|
|
.BorderBackgroundColor( FLinearColor( .6, .6, .6, 1.0f ) )
|
|
.Padding( 3.0f )
|
|
[
|
|
SNew( STextBlock )
|
|
.Text( LOCTEXT( "AssetsReferencingPendingDeletedAssets", "Assets Referencing the Pending Deleted Assets" ) )
|
|
.Font( FAppStyle::GetFontStyle( "BoldFont" ) )
|
|
.ShadowOffset( FVector2D( 1.0f, 1.0f ) )
|
|
]
|
|
]
|
|
|
|
// The Assets Still Using The To-Be-Deleted Assets
|
|
+ SVerticalBox::Slot()
|
|
.FillHeight( 1.0f )
|
|
[
|
|
SDeleteAssetsDialog::MakeAssetViewForReferencerAssets()
|
|
]
|
|
]
|
|
]
|
|
|
|
+ SVerticalBox::Slot()
|
|
.AutoHeight()
|
|
.Padding( 5.0f )
|
|
[
|
|
SNew( SBorder )
|
|
.BorderImage( FAppStyle::GetBrush( "ToolPanel.GroupBorder" ) )
|
|
.Padding( 0 )
|
|
[
|
|
SNew( SVerticalBox )
|
|
|
|
// How do you want to handle this?
|
|
+ SVerticalBox::Slot()
|
|
.AutoHeight()
|
|
[
|
|
SNew( SBorder )
|
|
.BorderImage( FAppStyle::GetBrush( "DetailsView.CategoryTop" ) )
|
|
.BorderBackgroundColor( FLinearColor( .6, .6, .6, 1.0f ) )
|
|
.Padding( 3.0f )
|
|
[
|
|
SNew( SHorizontalBox )
|
|
|
|
+ SHorizontalBox::Slot()
|
|
.FillWidth( 1.0f )
|
|
.HAlign( HAlign_Center )
|
|
[
|
|
SNew( STextBlock )
|
|
.Text( this, &SDeleteAssetsDialog::GetHandleText )
|
|
.Font( FAppStyle::GetFontStyle( "BoldFont" ) )
|
|
.ShadowOffset( FVector2D( 1.0f, 1.0f ) )
|
|
]
|
|
]
|
|
]
|
|
|
|
+ SVerticalBox::Slot()
|
|
.AutoHeight()
|
|
.Padding(6,4)
|
|
[
|
|
SAssignNew(DeleteSourceFilesCheckbox, SCheckBox)
|
|
.Visibility(this, &SDeleteAssetsDialog::GetDeleteSourceFilesVisibility)
|
|
.IsChecked(LoadingSavingSettings->bDeleteSourceFilesWithAssets ? ECheckBoxState::Checked : ECheckBoxState::Unchecked)
|
|
[
|
|
SNew(STextBlock)
|
|
.Text(LOCTEXT("DeleteSourceFiles", "Also delete related source content files"))
|
|
.ToolTip(
|
|
SNew(SToolTip)
|
|
.Text(this, &SDeleteAssetsDialog::GetDeleteSourceContentTooltip)
|
|
)
|
|
]
|
|
]
|
|
|
|
+ SVerticalBox::Slot()
|
|
.AutoHeight()
|
|
.Padding(0,4)
|
|
[
|
|
SNew( SHorizontalBox )
|
|
|
|
+ SHorizontalBox::Slot()
|
|
.FillWidth( 1.0f )
|
|
.Padding( 6, 0 )
|
|
[
|
|
SNew( SBorder )
|
|
.BorderImage( FAppStyle::GetBrush( "NoBorder" ) )
|
|
.Visibility( this, &SDeleteAssetsDialog::GetReplaceReferencesVisibility )
|
|
[
|
|
( DeleteModel->CanReplaceReferences() ? BuildReplaceReferencesWidget() : BuildCantUseReplaceReferencesWidget() )
|
|
]
|
|
]
|
|
|
|
+ SHorizontalBox::Slot()
|
|
.FillWidth( 1.0f )
|
|
.Padding( 6, 0 )
|
|
[
|
|
SNew( SBorder )
|
|
.BorderImage( FAppStyle::GetBrush( "NoBorder" ) )
|
|
.Visibility( this, &SDeleteAssetsDialog::GetForceDeleteVisibility )
|
|
[
|
|
BuildForceDeleteWidget()
|
|
]
|
|
]
|
|
|
|
+ SHorizontalBox::Slot()
|
|
.FillWidth( 1.0f )
|
|
.Padding( 6, 0 )
|
|
[
|
|
SNew( SBorder )
|
|
.BorderImage( FAppStyle::GetBrush( "NoBorder" ) )
|
|
.Visibility( this, &SDeleteAssetsDialog::GetDeleteVisibility )
|
|
[
|
|
SNew( SButton )
|
|
.HAlign( HAlign_Center )
|
|
.Text( LOCTEXT( "Delete", "Delete" ) )
|
|
.ToolTipText( LOCTEXT( "DeleteTooltipText", "Perform the delete" ) )
|
|
.ButtonStyle(FAppStyle::Get(), "FlatButton.Danger")
|
|
.TextStyle(FAppStyle::Get(), "FlatButton.DefaultTextStyle")
|
|
.OnClicked(this, &SDeleteAssetsDialog::Delete)
|
|
]
|
|
]
|
|
|
|
+ SHorizontalBox::Slot()
|
|
.FillWidth( 1.0f )
|
|
.Padding( 6, 0 )
|
|
[
|
|
SNew( SBorder )
|
|
.BorderImage( FAppStyle::GetBrush( "NoBorder" ) )
|
|
.VAlign( EVerticalAlignment::VAlign_Bottom )
|
|
[
|
|
SNew( SButton )
|
|
.HAlign( HAlign_Center )
|
|
.Text( LOCTEXT( "Cancel", "Cancel" ) )
|
|
.ToolTipText( LOCTEXT( "CancelDeleteTooltipText", "Cancel the delete" ) )
|
|
.ButtonStyle(FAppStyle::Get(), "FlatButton.Default")
|
|
.TextStyle(FAppStyle::Get(), "FlatButton.DefaultTextStyle")
|
|
.OnClicked( this, &SDeleteAssetsDialog::Cancel )
|
|
]
|
|
]
|
|
]
|
|
]
|
|
];
|
|
}
|
|
|
|
FText SDeleteAssetsDialog::GetHandleText() const
|
|
{
|
|
if ( CanDelete() )
|
|
{
|
|
return LOCTEXT( "AreYouSure", "Are you sure you want to delete these assets?" );
|
|
}
|
|
else
|
|
{
|
|
return LOCTEXT( "HandleIt", "How do you want to handle this?" );
|
|
}
|
|
}
|
|
|
|
FText SDeleteAssetsDialog::GetDeleteSourceContentTooltip() const
|
|
{
|
|
FString AllFiles;
|
|
|
|
static const int32 MaxNumPathsToShow = 25;
|
|
const auto& AllFileCounts = DeleteModel->GetPendingDeletedSourceFileCounts();
|
|
int32 TotalCount = 0, NumPrinted = 0;
|
|
for (const auto& PathAndAssetCount : AllFileCounts)
|
|
{
|
|
// If this path is no longer referenced by deleted files, it's toast.
|
|
if (PathAndAssetCount.Value == 0)
|
|
{
|
|
++TotalCount;
|
|
|
|
if (TotalCount <= MaxNumPathsToShow)
|
|
{
|
|
if (NumPrinted != 0)
|
|
{
|
|
AllFiles += TEXT("\n");
|
|
}
|
|
|
|
AllFiles += PathAndAssetCount.Key;
|
|
++NumPrinted;
|
|
}
|
|
}
|
|
}
|
|
|
|
FText RootText;
|
|
|
|
FFormatOrderedArguments Args;
|
|
Args.Add(FText::FromString(AllFiles));
|
|
|
|
if (NumPrinted < TotalCount)
|
|
{
|
|
Args.Add(FText::AsNumber(TotalCount - NumPrinted));
|
|
RootText = LOCTEXT("DeleteSourceFilesAndMore_Tooltip", "When checked, the following source content files will also be deleted along with the assets:\n\n{0}\n... and {1} more.");
|
|
}
|
|
else
|
|
{
|
|
RootText = LOCTEXT("DeleteSourceFiles_Tooltip", "When checked, the following source content files will also be deleted along with the assets:\n\n{0}");
|
|
}
|
|
|
|
return FText::Format(RootText, Args);
|
|
}
|
|
|
|
EVisibility SDeleteAssetsDialog::GetAssetReferencesVisiblity() const
|
|
{
|
|
return DeleteModel->GetAssetReferences().Num() == 0 ? EVisibility::Collapsed : EVisibility::Visible;
|
|
}
|
|
|
|
TSharedRef<SWidget> SDeleteAssetsDialog::BuildCantUseReplaceReferencesWidget()
|
|
{
|
|
return SNew( STextBlock )
|
|
.AutoWrapText( true )
|
|
.Text( LOCTEXT( "ReplaceReferencesNotAvailabeText", "Not all objects are compatible, so Replace References is unavailable." ) );
|
|
}
|
|
|
|
TSharedRef<SWidget> SDeleteAssetsDialog::BuildReplaceReferencesWidget()
|
|
{
|
|
return SNew( SVerticalBox )
|
|
|
|
+ SVerticalBox::Slot()
|
|
.FillHeight( 1 )
|
|
.Padding( 0, 0, 0, 3 )
|
|
[
|
|
SNew( STextBlock )
|
|
.AutoWrapText( true )
|
|
//.Font( FAppStyle::GetFontStyle( "BoldFont" ) )
|
|
.Text( LOCTEXT( "ReplaceReferencesText", "Delete the assets and update referencers to point at an asset of your choosing." ) )
|
|
]
|
|
|
|
+ SVerticalBox::Slot()
|
|
.AutoHeight()
|
|
[
|
|
SAssignNew( ConsolidationPickerComboButton, SComboButton )
|
|
.HAlign( EHorizontalAlignment::HAlign_Fill )
|
|
.VAlign( EVerticalAlignment::VAlign_Center )
|
|
.ComboButtonStyle( FAppStyle::Get(), "ToolbarComboButton" )
|
|
.ForegroundColor( FLinearColor::White )
|
|
.ContentPadding( 3 )
|
|
.MenuPlacement( EMenuPlacement::MenuPlacement_BelowAnchor )
|
|
.OnGetMenuContent( this, &SDeleteAssetsDialog::MakeConsolidationAssetPicker )
|
|
.ButtonContent()
|
|
[
|
|
SNew(SHorizontalBox)
|
|
|
|
+ SHorizontalBox::Slot()
|
|
.AutoWidth()
|
|
[
|
|
CreateThumbnailWidget()
|
|
]
|
|
|
|
+ SHorizontalBox::Slot()
|
|
.FillWidth( 1.0f )
|
|
.VAlign( VAlign_Center )
|
|
.Padding(5, 0)
|
|
[
|
|
SNew( STextBlock )
|
|
.Text( this, &SDeleteAssetsDialog::GetConsolidateAssetName )
|
|
]
|
|
]
|
|
]
|
|
|
|
+ SVerticalBox::Slot()
|
|
.AutoHeight()
|
|
[
|
|
SNew( SButton )
|
|
.HAlign( HAlign_Center )
|
|
.Text( LOCTEXT( "Replace References", "Replace References" ) )
|
|
.OnClicked( this, &SDeleteAssetsDialog::ReplaceReferences )
|
|
.ButtonStyle(FAppStyle::Get(), "FlatButton.Danger")
|
|
.TextStyle(FAppStyle::Get(), "FlatButton.DefaultTextStyle")
|
|
];
|
|
}
|
|
|
|
TSharedRef<SWidget> SDeleteAssetsDialog::BuildForceDeleteWidget()
|
|
{
|
|
return SNew( SVerticalBox )
|
|
|
|
+ SVerticalBox::Slot()
|
|
.FillHeight( 1.0f )
|
|
.Padding( 0, 0, 0, 3.0f )
|
|
[
|
|
SNew( STextBlock )
|
|
.AutoWrapText( true )
|
|
//.Font( FAppStyle::GetFontStyle( "BoldFont" ) )
|
|
.Text( LOCTEXT( "ForceDeleteText", "Delete the asset anyway, but referencers may not work correctly anymore.\n\nUse as a last resort." ) )
|
|
]
|
|
|
|
+ SVerticalBox::Slot()
|
|
.AutoHeight()
|
|
[
|
|
SNew( SButton )
|
|
.HAlign( HAlign_Center )
|
|
.Text( LOCTEXT( "ForceDelete", "Force Delete" ) )
|
|
.ToolTipText( LOCTEXT( "ForceDeleteTooltipText", "Force Delete will obliterate all references to this asset and is dangerous.\n\nUse as a last resort." ) )
|
|
.ButtonStyle(FAppStyle::Get(), "FlatButton.Danger")
|
|
.TextStyle(FAppStyle::Get(), "FlatButton.DefaultTextStyle")
|
|
.OnClicked(this, &SDeleteAssetsDialog::ForceDelete)
|
|
];
|
|
}
|
|
|
|
FReply SDeleteAssetsDialog::OnKeyDown( const FGeometry& MyGeometry, const FKeyEvent& InKeyEvent )
|
|
{
|
|
if( InKeyEvent.GetKey() == EKeys::Escape )
|
|
{
|
|
ParentWindow.Get()->RequestDestroyWindow();
|
|
return FReply::Handled();
|
|
}
|
|
|
|
if ( ReferencerCommands->ProcessCommandBindings(InKeyEvent) )
|
|
{
|
|
return FReply::Handled();
|
|
}
|
|
return FReply::Unhandled();
|
|
}
|
|
|
|
EActiveTimerReturnType SDeleteAssetsDialog::TickDeleteModel( double InCurrentTime, float InDeltaTime )
|
|
{
|
|
DeleteModel->Tick( InDeltaTime );
|
|
|
|
if ( DeleteModel->GetState() == FAssetDeleteModel::EState::Finished )
|
|
{
|
|
bIsActiveTimerRegistered = false;
|
|
return EActiveTimerReturnType::Stop;
|
|
}
|
|
|
|
return EActiveTimerReturnType::Continue;
|
|
}
|
|
|
|
void SDeleteAssetsDialog::HandleDeleteModelStateChanged(FAssetDeleteModel::EState NewState)
|
|
{
|
|
switch ( NewState )
|
|
{
|
|
case FAssetDeleteModel::StartScanning:
|
|
RootContainer->SetContent( BuildProgressDialog() );
|
|
break;
|
|
case FAssetDeleteModel::Finished:
|
|
RootContainer->SetContent( BuildDeleteDialog() );
|
|
break;
|
|
case FAssetDeleteModel::Scanning:
|
|
case FAssetDeleteModel::UpdateActions:
|
|
case FAssetDeleteModel::Waiting:
|
|
break;
|
|
}
|
|
}
|
|
|
|
FText SDeleteAssetsDialog::ScanningText() const
|
|
{
|
|
return DeleteModel->GetProgressText();
|
|
}
|
|
|
|
TOptional< float > SDeleteAssetsDialog::ScanningProgressFraction() const
|
|
{
|
|
return DeleteModel->GetProgress();
|
|
}
|
|
|
|
TSharedRef<SWidget> SDeleteAssetsDialog::CreateThumbnailWidget()
|
|
{
|
|
ConsolidationAssetThumbnail = MakeShareable( new FAssetThumbnail( NULL, 40, 40, UThumbnailManager::Get().GetSharedThumbnailPool()) );
|
|
|
|
return SNew( SBox )
|
|
.WidthOverride( 40.0f )
|
|
.HeightOverride( 40.0f )
|
|
[
|
|
ConsolidationAssetThumbnail->MakeThumbnailWidget()
|
|
];
|
|
}
|
|
|
|
EVisibility SDeleteAssetsDialog::GetReferencesVisiblity() const
|
|
{
|
|
return DeleteModel->IsAnythingReferencedInMemoryByNonUndo() ? EVisibility::Visible : EVisibility::Collapsed;
|
|
}
|
|
|
|
EVisibility SDeleteAssetsDialog::GetUndoVisiblity() const
|
|
{
|
|
return DeleteModel->IsAnythingReferencedInMemoryByUndo() ? EVisibility::Visible : EVisibility::Collapsed;
|
|
}
|
|
|
|
TSharedRef<ITableRow> SDeleteAssetsDialog::HandleGenerateAssetRow( TSharedPtr<FPendingDelete> InItem, const TSharedRef<STableViewBase>& OwnerTable )
|
|
{
|
|
return SNew(SPendingDeleteRow, OwnerTable, InItem)
|
|
.Visibility(InItem->IsInternal() ? EVisibility::Collapsed : EVisibility::Visible);
|
|
}
|
|
|
|
void SDeleteAssetsDialog::DeleteRelevantSourceContent()
|
|
{
|
|
if (DeleteModel->HasAnySourceContentFilesToDelete())
|
|
{
|
|
auto* Settings = GetMutableDefault<UEditorLoadingSavingSettings>();
|
|
if (DeleteSourceFilesCheckbox->GetCheckedState() == ECheckBoxState::Checked)
|
|
{
|
|
Settings->bDeleteSourceFilesWithAssets = true;
|
|
DeleteModel->DeleteSourceContentFiles();
|
|
}
|
|
else
|
|
{
|
|
Settings->bDeleteSourceFilesWithAssets = false;
|
|
}
|
|
}
|
|
}
|
|
|
|
FReply SDeleteAssetsDialog::Delete()
|
|
{
|
|
ParentWindow.Get()->RequestDestroyWindow();
|
|
|
|
if (DeleteModel->IsAnythingReferencedInMemoryByUndo())
|
|
{
|
|
GEditor->Trans->Reset(LOCTEXT("DeleteSelectedItem", "Delete Selected Item"));
|
|
}
|
|
|
|
DeleteRelevantSourceContent();
|
|
DeleteModel->DoDelete();
|
|
|
|
return FReply::Handled();
|
|
}
|
|
|
|
FReply SDeleteAssetsDialog::Cancel()
|
|
{
|
|
ParentWindow.Get()->RequestDestroyWindow();
|
|
|
|
return FReply::Handled();
|
|
}
|
|
|
|
FReply SDeleteAssetsDialog::ForceDelete()
|
|
{
|
|
ParentWindow.Get()->RequestDestroyWindow();
|
|
|
|
if( DeleteModel->IsAnythingReferencedInMemoryByUndo() )
|
|
{
|
|
GEditor->Trans->Reset( LOCTEXT("DeleteSelectedItem", "Delete Selected Item") );
|
|
}
|
|
|
|
DeleteRelevantSourceContent();
|
|
DeleteModel->DoForceDelete();
|
|
|
|
return FReply::Handled();
|
|
}
|
|
|
|
FText SDeleteAssetsDialog::GetConsolidateAssetName() const
|
|
{
|
|
if ( !ConsolidationAsset.IsValid() )
|
|
{
|
|
return LOCTEXT( "None", "None" );
|
|
}
|
|
else
|
|
{
|
|
return FText::FromName(ConsolidationAsset.AssetName);
|
|
}
|
|
}
|
|
|
|
FReply SDeleteAssetsDialog::ReplaceReferences()
|
|
{
|
|
if ( !ConsolidationAsset.IsValid() )
|
|
{
|
|
return FReply::Handled();
|
|
}
|
|
|
|
FText Message = FText::Format( LOCTEXT( "ReplaceMessage", "This will replace any reference to the pending deleted assets with {0}; and then delete them.\n\nAre you sure?" ), FText::FromName( ConsolidationAsset.AssetName ) );
|
|
FText Title = LOCTEXT( "ReplaceTitle", "Replace References?" );
|
|
|
|
if ( EAppReturnType::Ok == FMessageDialog::Open( EAppMsgType::OkCancel, Message, &Title ) )
|
|
{
|
|
ParentWindow.Get()->RequestDestroyWindow();
|
|
DeleteRelevantSourceContent();
|
|
DeleteModel->DoReplaceReferences( ConsolidationAsset );
|
|
}
|
|
|
|
return FReply::Handled();
|
|
}
|
|
|
|
TSharedRef<SWidget> SDeleteAssetsDialog::MakeAssetViewForReferencerAssets()
|
|
{
|
|
FContentBrowserModule& ContentBrowserModule = FModuleManager::Get().LoadModuleChecked<FContentBrowserModule>(TEXT("ContentBrowser"));
|
|
|
|
FAssetPickerConfig AssetPickerConfig;
|
|
|
|
AssetPickerConfig.bAllowDragging = false;
|
|
AssetPickerConfig.bCanShowClasses = false;
|
|
AssetPickerConfig.bAllowNullSelection = false;
|
|
AssetPickerConfig.bShowBottomToolbar = false;
|
|
AssetPickerConfig.bAutohideSearchBar = true;
|
|
AssetPickerConfig.bPreloadAssetsForContextMenu = false;
|
|
|
|
AssetPickerConfig.AssetShowWarningText = TAttribute< FText >( this, &SDeleteAssetsDialog::GetReferencingAssetsEmptyText );
|
|
|
|
AssetPickerConfig.InitialAssetViewType = EAssetViewType::Tile;
|
|
AssetPickerConfig.OnAssetsActivated = FOnAssetsActivated::CreateSP(this, &SDeleteAssetsDialog::OnAssetsActivated);
|
|
AssetPickerConfig.OnShouldFilterAsset = FOnShouldFilterAsset::CreateSP(this, &SDeleteAssetsDialog::OnShouldFilterAsset);
|
|
AssetPickerConfig.OnGetAssetContextMenu = FOnGetAssetContextMenu::CreateSP( this, &SDeleteAssetsDialog::OnGetAssetContextMenu );
|
|
AssetPickerConfig.GetCurrentSelectionDelegates.Add( &GetSelectedReferencerAssets );
|
|
|
|
return ContentBrowserModule.Get().CreateAssetPicker(AssetPickerConfig);
|
|
}
|
|
|
|
TSharedRef<SWidget> SDeleteAssetsDialog::MakeConsolidationAssetPicker()
|
|
{
|
|
FAssetPickerConfig AssetPickerConfig;
|
|
//AssetPickerConfig.Filter.ClassPaths.Add( UStaticMesh::StaticClass()->GetFName() );
|
|
AssetPickerConfig.OnAssetSelected = FOnAssetSelected::CreateSP( this, &SDeleteAssetsDialog::OnAssetSelectedFromConsolidationPicker );
|
|
AssetPickerConfig.OnShouldFilterAsset = FOnShouldFilterAsset::CreateSP( this, &SDeleteAssetsDialog::OnShouldConsolidationFilterAsset );
|
|
AssetPickerConfig.bAllowNullSelection = false;
|
|
AssetPickerConfig.InitialAssetViewType = EAssetViewType::List;
|
|
AssetPickerConfig.bFocusSearchBoxWhenOpened = true;
|
|
AssetPickerConfig.bShowBottomToolbar = true;
|
|
AssetPickerConfig.bAllowDragging = false;
|
|
AssetPickerConfig.bCanShowClasses = false;
|
|
AssetPickerConfig.bPreloadAssetsForContextMenu = false;
|
|
AssetPickerConfig.SelectionMode = ESelectionMode::Single;
|
|
|
|
FContentBrowserModule& ContentBrowserModule = FModuleManager::Get().LoadModuleChecked<FContentBrowserModule>( TEXT( "ContentBrowser" ) );
|
|
|
|
return SNew( SBox )
|
|
.HeightOverride( 250 )
|
|
.WidthOverride( 300 )
|
|
[
|
|
ContentBrowserModule.Get().CreateAssetPicker( AssetPickerConfig )
|
|
];
|
|
}
|
|
|
|
FText SDeleteAssetsDialog::GetReferencingAssetsEmptyText() const
|
|
{
|
|
FString DiskReferences = "There Are Some Non-Displayable References\n\n";
|
|
|
|
for ( const FName& DiskReference : DeleteModel->GetAssetReferences() )
|
|
{
|
|
DiskReferences += DiskReference.ToString() + "\n";
|
|
}
|
|
|
|
return FText::FromString( DiskReferences );
|
|
}
|
|
|
|
/** Handler for when the user double clicks, presses enter, or presses space on an asset */
|
|
void SDeleteAssetsDialog::OnAssetsActivated(const TArray<FAssetData>& ActivatedAssets, EAssetTypeActivationMethod::Type ActivationMethod)
|
|
{
|
|
// Open a simple asset editor for all assets which do not have asset type actions if activating with enter or double click
|
|
if ( ActivationMethod == EAssetTypeActivationMethod::DoubleClicked || ActivationMethod == EAssetTypeActivationMethod::Opened )
|
|
{
|
|
ParentWindow.Get()->RequestDestroyWindow();
|
|
|
|
for(const FAssetData& ActivatedAsset : ActivatedAssets)
|
|
{
|
|
FString MapFilePath;
|
|
if ( FEditorFileUtils::IsMapPackageAsset(ActivatedAsset.ObjectPath.ToString(), MapFilePath) )
|
|
{
|
|
if ( ActivatedAsset.IsAssetLoaded() )
|
|
{
|
|
DeleteModel->GoToNextReferenceInLevel();
|
|
}
|
|
else
|
|
{
|
|
if ( !GIsDemoMode )
|
|
{
|
|
// If there are any unsaved changes to the current level, see if the user wants to save those first.
|
|
bool bPromptUserToSave = true;
|
|
bool bSaveMapPackages = true;
|
|
bool bSaveContentPackages = true;
|
|
if ( FEditorFileUtils::SaveDirtyPackages(bPromptUserToSave, bSaveMapPackages, bSaveContentPackages) == false )
|
|
{
|
|
// something went wrong or the user pressed cancel. Return to the editor so the user doesn't lose their changes
|
|
return;
|
|
}
|
|
}
|
|
|
|
FEditorDirectories::Get().SetLastDirectory(ELastDirectory::LEVEL, FPaths::GetPath(MapFilePath));
|
|
FEditorFileUtils::LoadMap(MapFilePath, false, true);
|
|
|
|
// @todo ndarnell Now that the map is loading how do i select the first reference...
|
|
}
|
|
}
|
|
else
|
|
{
|
|
GEditor->GetEditorSubsystem<UAssetEditorSubsystem>()->OpenEditorForAsset(ActivatedAsset.GetAsset());
|
|
|
|
// @todo ndarnell select in content browser maybe as well?
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
EVisibility SDeleteAssetsDialog::GetReplaceReferencesVisibility() const
|
|
{
|
|
// We can't replace references if nobody is referencing the pending deleted assets
|
|
if ( DeleteModel->GetAssetReferences().Num() == 0 )
|
|
{
|
|
return EVisibility::Collapsed;
|
|
}
|
|
|
|
return EVisibility::Visible;
|
|
}
|
|
|
|
EVisibility SDeleteAssetsDialog::GetForceDeleteVisibility() const
|
|
{
|
|
return CanForceDelete() ? EVisibility::Visible : EVisibility::Collapsed;
|
|
}
|
|
|
|
EVisibility SDeleteAssetsDialog::GetDeleteVisibility() const
|
|
{
|
|
return CanDelete() ? EVisibility::Visible : EVisibility::Collapsed;
|
|
}
|
|
|
|
EVisibility SDeleteAssetsDialog::GetDeleteSourceFilesVisibility() const
|
|
{
|
|
return DeleteModel->HasAnySourceContentFilesToDelete() ? EVisibility::Visible : EVisibility::Collapsed;
|
|
}
|
|
|
|
bool SDeleteAssetsDialog::CanReplaceReferences() const
|
|
{
|
|
return DeleteModel->CanReplaceReferences();
|
|
}
|
|
|
|
bool SDeleteAssetsDialog::CanForceDelete() const
|
|
{
|
|
return DeleteModel->CanForceDelete();
|
|
}
|
|
|
|
bool SDeleteAssetsDialog::CanDelete() const
|
|
{
|
|
return DeleteModel->CanDelete();
|
|
}
|
|
|
|
bool SDeleteAssetsDialog::OnShouldConsolidationFilterAsset( const FAssetData& InAssetData ) const
|
|
{
|
|
return DeleteModel->CanReplaceReferencesWith( InAssetData );
|
|
}
|
|
|
|
TSharedPtr<SWidget> SDeleteAssetsDialog::OnGetAssetContextMenu( const TArray<FAssetData>& SelectedAssets )
|
|
{
|
|
// Get all menu extenders for this context menu from the content browser module
|
|
/*FContentBrowserModule& ContentBrowserModule = FModuleManager::GetModuleChecked<FContentBrowserModule>( TEXT( "ContentBrowser" ) );
|
|
TArray<FContentBrowserMenuExtender_SelectedAssets> MenuExtenderDelegates = ContentBrowserModule.GetAllAssetViewContextMenuExtenders();
|
|
|
|
TArray<TSharedPtr<FExtender>> Extenders;
|
|
for ( int32 i = 0; i < MenuExtenderDelegates.Num(); ++i )
|
|
{
|
|
if ( MenuExtenderDelegates[i].IsBound() )
|
|
{
|
|
Extenders.Add( MenuExtenderDelegates[i].Execute( SelectedAssets ) );
|
|
}
|
|
}*/
|
|
//TSharedPtr<FExtender> MenuExtender = FExtender::Combine( Extenders );
|
|
|
|
FMenuBuilder MenuBuilder(true, ReferencerCommands);
|
|
|
|
MenuBuilder.BeginSection("AssetOptions", LOCTEXT("AssetOptionsText", "Asset Options"));
|
|
{
|
|
MenuBuilder.AddMenuEntry( FGenericCommands::Get().Delete, NAME_None,
|
|
LOCTEXT( "AddPendingDelete", "Add to Pending Deletes" ),
|
|
LOCTEXT( "AddPendingDeleteTooltip", "Adds the selected assets to the list of pending deleted assets." )
|
|
);
|
|
}
|
|
MenuBuilder.EndSection();
|
|
|
|
return MenuBuilder.MakeWidget();
|
|
}
|
|
|
|
bool SDeleteAssetsDialog::CanExecuteDeleteReferencers() const
|
|
{
|
|
TArray<FAssetData> SelectedAssets = GetSelectedReferencerAssets.Execute();
|
|
return SelectedAssets.Num() > 0;
|
|
}
|
|
|
|
void SDeleteAssetsDialog::ExecuteDeleteReferencers()
|
|
{
|
|
TArray<FAssetData> SelectedAssets = GetSelectedReferencerAssets.Execute();
|
|
|
|
for ( const FAssetData& SelectedAsset : SelectedAssets )
|
|
{
|
|
UObject* ObjectToDelete = SelectedAsset.GetAsset();
|
|
if (ObjectToDelete)
|
|
{
|
|
DeleteModel->AddObjectToDelete(ObjectToDelete);
|
|
}
|
|
if ( !bIsActiveTimerRegistered )
|
|
{
|
|
bIsActiveTimerRegistered = true;
|
|
RegisterActiveTimer( 0.f, FWidgetActiveTimerDelegate::CreateSP( this, &SDeleteAssetsDialog::TickDeleteModel ) );
|
|
}
|
|
}
|
|
}
|
|
|
|
bool SDeleteAssetsDialog::OnShouldFilterAsset( const FAssetData& InAssetData ) const
|
|
{
|
|
// Filter out any redirectors that are not to the main UAsset
|
|
if ( InAssetData.IsRedirector() && !InAssetData.IsUAsset() )
|
|
{
|
|
return true;
|
|
}
|
|
|
|
// If it's in the set of references then don't filter it.
|
|
if ( DeleteModel->GetAssetReferences().Contains( InAssetData.PackageName ) )
|
|
{
|
|
return false;
|
|
}
|
|
|
|
return true;
|
|
}
|
|
|
|
void SDeleteAssetsDialog::OnAssetSelectedFromConsolidationPicker(const FAssetData& AssetData)
|
|
{
|
|
ConsolidationAssetThumbnail->SetAsset( AssetData );
|
|
ConsolidationAssetThumbnail->RefreshThumbnail();
|
|
|
|
ConsolidationAsset = AssetData;
|
|
ConsolidationPickerComboButton->SetIsOpen( false );
|
|
}
|
|
|
|
//////////////////////////////////////////////////////////////////////////
|
|
|
|
#undef LOCTEXT_NAMESPACE
|