Files
UnrealEngine/Engine/Source/Editor/UnrealEd/Private/Dialogs/SDeleteAssetsDialog.cpp
2025-05-18 13:04:45 +08:00

1036 lines
30 KiB
C++

// Copyright Epic Games, Inc. All Rights Reserved.
#include "Dialogs/SDeleteAssetsDialog.h"
#include "AssetRegistry/AssetData.h"
#include "AssetRegistry/AssetRegistryModule.h"
#include "AssetRegistry/IAssetRegistry.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 "Editor/Transactor.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.0f)
];
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.0f )
[
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.0f)
.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 )
{
if (TSharedPtr<SWindow> OwningWindow = ParentWindow.Pin())
{
OwningWindow->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()
{
if (TSharedPtr<SWindow> OwningWindow = ParentWindow.Pin())
{
OwningWindow->RequestDestroyWindow();
}
if (DeleteModel->IsAnythingReferencedInMemoryByUndo())
{
GEditor->Trans->Reset(LOCTEXT("DeleteSelectedItem", "Delete Selected Item"));
}
DeleteRelevantSourceContent();
DeleteModel->DoDelete();
return FReply::Handled();
}
FReply SDeleteAssetsDialog::Cancel()
{
if (TSharedPtr<SWindow> OwningWindow = ParentWindow.Pin())
{
OwningWindow->RequestDestroyWindow();
}
return FReply::Handled();
}
FReply SDeleteAssetsDialog::ForceDelete()
{
if (TSharedPtr<SWindow> OwningWindow = ParentWindow.Pin())
{
OwningWindow->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 ) )
{
if (TSharedPtr<SWindow> OwningWindow = ParentWindow.Pin())
{
OwningWindow->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.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.SelectionMode = ESelectionMode::Single;
AssetPickerConfig.bAddFilterUI = true;
FContentBrowserModule& ContentBrowserModule = FModuleManager::Get().LoadModuleChecked<FContentBrowserModule>( TEXT( "ContentBrowser" ) );
return SNew( SBox )
.HeightOverride( 250.0f )
.WidthOverride( 300.0f )
[
ContentBrowserModule.Get().CreateAssetPicker( AssetPickerConfig )
];
}
FText SDeleteAssetsDialog::GetReferencingAssetsEmptyText() const
{
FString DiskReferences = "There Are Some Non-Displayable References\n\n";
static FName NAME_ActorLabel(TEXT("ActorLabel"));
IAssetRegistry& AssetRegistry = FModuleManager::LoadModuleChecked<FAssetRegistryModule>(TEXT("AssetRegistry")).Get();
for ( const FName& DiskReference : DeleteModel->GetAssetReferences() )
{
FString ReferenceToAppend;
FARFilter Filter;
Filter.PackageNames = { DiskReference };
TArray<FAssetData> Assets;
if (AssetRegistry.GetAssets(Filter, Assets))
{
for (const FAssetData& Asset : Assets)
{
FString ActorLabel;
if (Asset.GetTagValue(NAME_ActorLabel, ActorLabel))
{
ReferenceToAppend = Asset.GetOptionalOuterPathName().ToString() + TEXT(".") + ActorLabel;
break;
}
}
}
if (ReferenceToAppend.IsEmpty())
{
ReferenceToAppend = DiskReference.ToString();
}
DiskReferences += ReferenceToAppend + TEXT("\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 )
{
if (TSharedPtr<SWindow> OwningWindow = ParentWindow.Pin())
{
OwningWindow->RequestDestroyWindow();
}
for(const FAssetData& ActivatedAsset : ActivatedAssets)
{
FString MapFilePath;
if (FEditorFileUtils::IsMapPackageAsset(ActivatedAsset.GetObjectPathString(), 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