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

907 lines
34 KiB
C++

// Copyright Epic Games, Inc. All Rights Reserved.
#include "CollectionContextMenu.h"
#include "CollectionViewTypes.h"
#include "CollectionViewUtils.h"
#include "Containers/UnrealString.h"
#include "ContentBrowserDelegates.h"
#include "ContentBrowserModule.h"
#include "ContentBrowserUtils.h"
#include "Delegates/Delegate.h"
#include "Framework/Application/SlateApplication.h"
#include "Framework/Commands/GenericCommands.h"
#include "Framework/Commands/UIAction.h"
#include "Framework/Commands/UICommandInfo.h"
#include "Framework/Commands/UICommandList.h"
#include "Framework/MultiBox/MultiBoxBuilder.h"
#include "Framework/MultiBox/MultiBoxExtender.h"
#include "Framework/SlateDelegates.h"
#include "HAL/Platform.h"
#include "HAL/PlatformCrt.h"
#include "ICollectionContainer.h"
#include "ICollectionSource.h"
#include "ISourceControlModule.h"
#include "ISourceControlProvider.h"
#include "ISourceControlState.h"
#include "Internationalization/Internationalization.h"
#include "Internationalization/Text.h"
#include "Math/Vector2D.h"
#include "Misc/AssertionMacros.h"
#include "Misc/Attribute.h"
#include "Misc/Optional.h"
#include "Modules/ModuleManager.h"
#include "SlotBase.h"
#include "TelemetryRouter.h"
#include "Styling/AppStyle.h"
#include "Textures/SlateIcon.h"
#include "UObject/NameTypes.h"
#include "UObject/UnrealNames.h"
#include "Widgets/Colors/SColorBlock.h"
#include "Widgets/Colors/SColorPicker.h"
#include "Widgets/DeclarativeSyntaxSupport.h"
#include "Widgets/Input/SButton.h"
#include "Widgets/SBoxPanel.h"
#include "Widgets/Views/STreeView.h"
class SWidget;
#define LOCTEXT_NAMESPACE "ContentBrowser"
FCollectionContextMenu::FCollectionContextMenu(const TWeakPtr<SCollectionView>& InCollectionView)
: CollectionView(InCollectionView)
, bCollectionsUnderSourceControl(false)
{
}
void FCollectionContextMenu::BindCommands(TSharedPtr< FUICommandList > InCommandList)
{
InCommandList->MapAction( FGenericCommands::Get().Rename, FUIAction(
FExecuteAction::CreateSP( this, &FCollectionContextMenu::ExecuteRenameCollection ),
FCanExecuteAction::CreateSP( this, &FCollectionContextMenu::CanExecuteRenameCollection )
));
}
TSharedPtr<SWidget> FCollectionContextMenu::MakeCollectionTreeContextMenu(TSharedPtr< FUICommandList > InCommandList)
{
// Get all menu extenders for this context menu from the content browser module
FContentBrowserModule& ContentBrowserModule = FModuleManager::GetModuleChecked<FContentBrowserModule>( TEXT("ContentBrowser") );
TArray<FContentBrowserMenuExtender> MenuExtenderDelegates = ContentBrowserModule.GetAllCollectionListContextMenuExtenders();
TArray<TSharedPtr<FExtender>> Extenders;
for (int32 i = 0; i < MenuExtenderDelegates.Num(); ++i)
{
if (MenuExtenderDelegates[i].IsBound())
{
Extenders.Add(MenuExtenderDelegates[i].Execute());
}
}
TSharedPtr<FExtender> MenuExtender = FExtender::Combine(Extenders);
FMenuBuilder MenuBuilder(/*bInShouldCloseWindowAfterMenuSelection=*/true, InCommandList, MenuExtender);
UpdateProjectSourceControl();
TSharedPtr<SCollectionView> CollectionViewPtr = CollectionView.Pin();
TArray<TSharedPtr<FCollectionItem>> SelectedCollections = CollectionViewPtr->CollectionTreePtr->GetSelectedItems();
bool bAnyManagedBySCC = false;
bool bAnyNeedSCCUpdate = false;
bool bAnyNeedSave = false;
bool bAnyWritable = false;
if (CollectionViewPtr->GetCollectionContainer().IsValid())
{
for (int32 CollectionIdx = 0; CollectionIdx < SelectedCollections.Num(); ++CollectionIdx)
{
if (CollectionViewPtr->GetCollectionContainer()->IsReadOnly(SelectedCollections[CollectionIdx]->CollectionType))
{
continue;
}
bAnyManagedBySCC |= SelectedCollections[CollectionIdx]->CollectionType != ECollectionShareType::CST_Local;
bAnyNeedSCCUpdate |= SelectedCollections[CollectionIdx]->CurrentStatus == ECollectionItemStatus::IsOutOfDate;
bAnyNeedSave |= SelectedCollections[CollectionIdx]->CurrentStatus == ECollectionItemStatus::HasLocalChanges;
bAnyWritable = true;
if (bAnyManagedBySCC && bAnyNeedSCCUpdate && bAnyNeedSave)
{
// Found collections to turn all options on, break now
break;
}
}
}
MenuBuilder.BeginSection("CollectionOptions", LOCTEXT("CollectionListOptionsMenuHeading", "Collection Options"));
{
const bool bHasSingleSelectedCollection = SelectedCollections.Num() == 1;
const bool bIsFirstSelectedCollectionReadOnly = SelectedCollections.Num() > 0 &&
(!CollectionViewPtr->GetCollectionContainer().IsValid() || CollectionViewPtr->GetCollectionContainer()->IsReadOnly(SelectedCollections[0]->CollectionType));
const bool bIsFirstSelectedCollectionStatic = SelectedCollections.Num() > 0 && SelectedCollections[0]->StorageMode == ECollectionStorageMode::Static;
{
TOptional<FCollectionNameType> ParentCollection;
if (SelectedCollections.Num() > 0)
{
ParentCollection = FCollectionNameType(SelectedCollections[0]->CollectionName, SelectedCollections[0]->CollectionType);
}
// New... (submenu)
MenuBuilder.AddSubMenu(
LOCTEXT("NewChildCollection", "New..."),
LOCTEXT("NewChildCollectionTooltip", "Create a child collection."),
FNewMenuDelegate::CreateRaw( this, &FCollectionContextMenu::MakeNewCollectionSubMenu, ECollectionStorageMode::Static, SCollectionView::FCreateCollectionPayload( ParentCollection ) ),
FUIAction(
FExecuteAction(),
FCanExecuteAction::CreateLambda( [=]{ return bHasSingleSelectedCollection && !bIsFirstSelectedCollectionReadOnly && bIsFirstSelectedCollectionStatic; } )
),
NAME_None,
EUserInterfaceActionType::Button
);
}
// Rename
MenuBuilder.AddMenuEntry( FGenericCommands::Get().Rename, NAME_None, LOCTEXT("RenameCollection", "Rename"), LOCTEXT("RenameCollectionTooltip", "Rename this collection."));
// Set Share Type
MenuBuilder.AddSubMenu(
LOCTEXT("SetCollectionShareType", "Set Share Type"),
LOCTEXT("SetCollectionShareTypeTooltip", "Change the share type of this collection."),
FNewMenuDelegate::CreateRaw( this, &FCollectionContextMenu::MakeCollectionShareTypeSubMenu ),
FUIAction(
FExecuteAction(),
FCanExecuteAction::CreateLambda( [=]{ return bHasSingleSelectedCollection && !bIsFirstSelectedCollectionReadOnly; } )
),
NAME_None,
EUserInterfaceActionType::Button
);
// If any colors have already been set, display color options as a sub menu
if ( CanExecuteColorChange() && CollectionViewUtils::HasCustomColors(*CollectionViewPtr->GetCollectionContainer()))
{
// Set Color (submenu)
MenuBuilder.AddSubMenu(
LOCTEXT("SetColor", "Set Color"),
LOCTEXT("SetCollectionColorTooltip", "Sets the color this collection should appear as."),
FNewMenuDelegate::CreateRaw( this, &FCollectionContextMenu::MakeSetColorSubMenu )
);
}
else
{
// Set Color
MenuBuilder.AddMenuEntry(
LOCTEXT("SetColor", "Set Color"),
LOCTEXT("SetCollectionColorTooltip", "Sets the color this collection should appear as."),
FSlateIcon(),
FUIAction(
FExecuteAction::CreateSP( this, &FCollectionContextMenu::ExecutePickColor ),
FCanExecuteAction::CreateSP( this, &FCollectionContextMenu::CanExecuteColorChange )
)
);
}
}
MenuBuilder.EndSection();
if ( SelectedCollections.Num() > 0 )
{
MenuBuilder.BeginSection("CollectionBulkOperations", LOCTEXT("CollectionListBulkOperationsMenuHeading", "Bulk Operations"));
{
// Save
MenuBuilder.AddMenuEntry(
LOCTEXT("SaveCollection", "Save"),
LOCTEXT("SaveCollectionTooltip", "Save this collection."),
FSlateIcon(),
FUIAction(
FExecuteAction::CreateSP( this, &FCollectionContextMenu::ExecuteSaveCollection ),
FCanExecuteAction::CreateLambda( [=]{ return bAnyNeedSave; } )
)
);
// Delete
MenuBuilder.AddMenuEntry(
LOCTEXT("DestroyCollection", "Delete"),
LOCTEXT("DestroyCollectionTooltip", "Delete this collection."),
FSlateIcon(),
FUIAction(
FExecuteAction::CreateSP( this, &FCollectionContextMenu::ExecuteDestroyCollection ),
FCanExecuteAction::CreateSP( this, &FCollectionContextMenu::CanExecuteDestroyCollection, bAnyManagedBySCC, bAnyWritable )
)
);
// Update
MenuBuilder.AddMenuEntry(
LOCTEXT("UpdateCollection", "Update"),
LOCTEXT("UpdateCollectionTooltip", "Update this collection to make sure it's using the latest version from revision control."),
FSlateIcon(),
FUIAction(
FExecuteAction::CreateSP( this, &FCollectionContextMenu::ExecuteUpdateCollection ),
FCanExecuteAction::CreateLambda( [=]{ return bAnyNeedSCCUpdate; } )
)
);
// Refresh
MenuBuilder.AddMenuEntry(
LOCTEXT("RefreshCollection", "Refresh"),
LOCTEXT("RefreshCollectionTooltip", "Refresh the revision control status of this collection."),
FSlateIcon(),
FUIAction(
FExecuteAction::CreateSP( this, &FCollectionContextMenu::ExecuteRefreshCollection ),
FCanExecuteAction::CreateLambda( [=]{ return bAnyManagedBySCC; } )
)
);
}
MenuBuilder.EndSection();
}
return MenuBuilder.MakeWidget();
}
void FCollectionContextMenu::MakeNewCollectionSubMenu(FMenuBuilder& MenuBuilder, ECollectionStorageMode::Type StorageMode, SCollectionView::FCreateCollectionPayload InCreationPayload)
{
const FText MenuHeading = FText::Format(
(InCreationPayload.ParentCollection.IsSet()) ? LOCTEXT("NewXChildCollectionMenuHeading", "New {0} Child Collection") : LOCTEXT("NewXCollectionMenuHeading", "New {0} Collection"),
ECollectionStorageMode::ToText(StorageMode)
);
MenuBuilder.BeginSection("CollectionNewCollection", MenuHeading);
{
const bool bCanCreateSharedChildren = !InCreationPayload.ParentCollection.IsSet() || ECollectionShareType::IsValidChildType( InCreationPayload.ParentCollection->Type, ECollectionShareType::CST_Shared );
MenuBuilder.AddMenuEntry(
LOCTEXT("NewCollection_Shared", "Shared Collection"),
LOCTEXT("NewCollection_SharedTooltip", "Create a collection that can be seen by anyone."),
FSlateIcon( FAppStyle::GetAppStyleSetName(), ECollectionShareType::GetIconStyleName( ECollectionShareType::CST_Shared ) ),
FUIAction(
FExecuteAction::CreateSP( this, &FCollectionContextMenu::ExecuteNewCollection, ECollectionShareType::CST_Shared, StorageMode, InCreationPayload ),
FCanExecuteAction::CreateSP( this, &FCollectionContextMenu::CanExecuteNewCollection, ECollectionShareType::CST_Shared, bCanCreateSharedChildren )
)
);
const bool bCanCreatePrivateChildren = !InCreationPayload.ParentCollection.IsSet() || ECollectionShareType::IsValidChildType( InCreationPayload.ParentCollection->Type, ECollectionShareType::CST_Private );
MenuBuilder.AddMenuEntry(
LOCTEXT("NewCollection_Private", "Private Collection"),
LOCTEXT("NewCollection_PrivateTooltip", "Create a collection that can only be seen by you."),
FSlateIcon( FAppStyle::GetAppStyleSetName(), ECollectionShareType::GetIconStyleName( ECollectionShareType::CST_Private ) ),
FUIAction(
FExecuteAction::CreateSP( this, &FCollectionContextMenu::ExecuteNewCollection, ECollectionShareType::CST_Private, StorageMode, InCreationPayload ),
FCanExecuteAction::CreateSP( this, &FCollectionContextMenu::CanExecuteNewCollection, ECollectionShareType::CST_Private, bCanCreatePrivateChildren )
)
);
const bool bCanCreateLocalChildren = !InCreationPayload.ParentCollection.IsSet() || ECollectionShareType::IsValidChildType( InCreationPayload.ParentCollection->Type, ECollectionShareType::CST_Local );
MenuBuilder.AddMenuEntry(
LOCTEXT("NewCollection_Local", "Local Collection"),
LOCTEXT("NewCollection_LocalTooltip", "Create a collection that is not in revision control and can only be seen by you."),
FSlateIcon( FAppStyle::GetAppStyleSetName(), ECollectionShareType::GetIconStyleName( ECollectionShareType::CST_Local ) ),
FUIAction(
FExecuteAction::CreateSP( this, &FCollectionContextMenu::ExecuteNewCollection, ECollectionShareType::CST_Local, StorageMode, InCreationPayload ),
FCanExecuteAction::CreateSP( this, &FCollectionContextMenu::CanExecuteNewCollection, ECollectionShareType::CST_Local, bCanCreateLocalChildren )
)
);
}
MenuBuilder.EndSection();
}
void FCollectionContextMenu::MakeSaveDynamicCollectionSubMenu(FMenuBuilder& MenuBuilder, FText InSearchQuery)
{
auto OnCollectionCreated = FCollectionItem::FCollectionCreatedEvent::CreateSP(this, &FCollectionContextMenu::ExecuteSaveDynamicCollection, InSearchQuery);
// Create new root level collection
MakeNewCollectionSubMenu(MenuBuilder, ECollectionStorageMode::Dynamic, SCollectionView::FCreateCollectionPayload(OnCollectionCreated));
TSharedPtr<SCollectionView> CollectionViewPtr = CollectionView.Pin();
if (!CollectionViewPtr->GetCollectionContainer())
{
return;
}
TArray<FCollectionNameType> AvailableCollections;
CollectionViewPtr->GetCollectionContainer()->GetCollections(AvailableCollections);
AvailableCollections.Sort([](const FCollectionNameType& One, const FCollectionNameType& Two) -> bool
{
return One.Name.LexicalLess(Two.Name);
});
if (AvailableCollections.Num() > 0)
{
MenuBuilder.BeginSection("CollectionReplaceCollection", LOCTEXT("OverwriteDynamicCollectionMenuHeading", "Overwrite Dynamic Collection"));
for (const FCollectionNameType& AvailableCollection : AvailableCollections)
{
// Never display system collections
if (AvailableCollection.Type == ECollectionShareType::CST_System)
{
continue;
}
// Can only overwrite dynamic collections
ECollectionStorageMode::Type StorageMode = ECollectionStorageMode::Static;
CollectionViewPtr->GetCollectionContainer()->GetCollectionStorageMode(AvailableCollection.Name, AvailableCollection.Type, StorageMode);
if (StorageMode != ECollectionStorageMode::Dynamic)
{
continue;
}
MenuBuilder.AddMenuEntry(
FText::FromName(AvailableCollection.Name),
FText::Format(LOCTEXT("SaveDynamicCollection_OverwriteExistingCollectionToolTip", "Overwrite '{0}' with the current search query"), FText::FromName(AvailableCollection.Name)),
FSlateIcon(FAppStyle::GetAppStyleSetName(), ECollectionShareType::GetIconStyleName(AvailableCollection.Type)),
FUIAction(
FExecuteAction::CreateSP( this, &FCollectionContextMenu::ExecuteSaveDynamicCollection, AvailableCollection, InSearchQuery ),
FCanExecuteAction::CreateSP( this, &FCollectionContextMenu::CanExecuteSaveDynamicCollection, AvailableCollection )
)
);
}
MenuBuilder.EndSection();
}
}
void FCollectionContextMenu::MakeCollectionShareTypeSubMenu(FMenuBuilder& MenuBuilder)
{
MenuBuilder.BeginSection("CollectionShareType", LOCTEXT("CollectionShareTypeMenuHeading", "Collection Share Type"));
{
MenuBuilder.AddMenuEntry(
ECollectionShareType::ToText( ECollectionShareType::CST_Shared ),
ECollectionShareType::GetDescription( ECollectionShareType::CST_Shared ),
FSlateIcon( FAppStyle::GetAppStyleSetName(), ECollectionShareType::GetIconStyleName( ECollectionShareType::CST_Shared ) ),
FUIAction(
FExecuteAction::CreateSP( this, &FCollectionContextMenu::ExecuteSetCollectionShareType, ECollectionShareType::CST_Shared ),
FCanExecuteAction::CreateSP( this, &FCollectionContextMenu::CanExecuteSetCollectionShareType, ECollectionShareType::CST_Shared ),
FIsActionChecked::CreateSP( this, &FCollectionContextMenu::IsSetCollectionShareTypeChecked, ECollectionShareType::CST_Shared )
),
NAME_None,
EUserInterfaceActionType::Check
);
MenuBuilder.AddMenuEntry(
ECollectionShareType::ToText( ECollectionShareType::CST_Private ),
ECollectionShareType::GetDescription( ECollectionShareType::CST_Private ),
FSlateIcon( FAppStyle::GetAppStyleSetName(), ECollectionShareType::GetIconStyleName( ECollectionShareType::CST_Private ) ),
FUIAction(
FExecuteAction::CreateSP( this, &FCollectionContextMenu::ExecuteSetCollectionShareType, ECollectionShareType::CST_Private ),
FCanExecuteAction::CreateSP( this, &FCollectionContextMenu::CanExecuteSetCollectionShareType, ECollectionShareType::CST_Private ),
FIsActionChecked::CreateSP( this, &FCollectionContextMenu::IsSetCollectionShareTypeChecked, ECollectionShareType::CST_Private )
),
NAME_None,
EUserInterfaceActionType::Check
);
MenuBuilder.AddMenuEntry(
ECollectionShareType::ToText( ECollectionShareType::CST_Local ),
ECollectionShareType::GetDescription( ECollectionShareType::CST_Local ),
FSlateIcon( FAppStyle::GetAppStyleSetName(), ECollectionShareType::GetIconStyleName( ECollectionShareType::CST_Local ) ),
FUIAction(
FExecuteAction::CreateSP( this, &FCollectionContextMenu::ExecuteSetCollectionShareType, ECollectionShareType::CST_Local ),
FCanExecuteAction::CreateSP( this, &FCollectionContextMenu::CanExecuteSetCollectionShareType, ECollectionShareType::CST_Local ),
FIsActionChecked::CreateSP( this, &FCollectionContextMenu::IsSetCollectionShareTypeChecked, ECollectionShareType::CST_Local )
),
NAME_None,
EUserInterfaceActionType::Check
);
}
MenuBuilder.EndSection();
}
void FCollectionContextMenu::MakeSetColorSubMenu(FMenuBuilder& MenuBuilder)
{
TSharedPtr<SCollectionView> CollectionViewPtr = CollectionView.Pin();
// New Color
MenuBuilder.AddMenuEntry(
LOCTEXT("NewColor", "New Color"),
LOCTEXT("NewCollectionColorTooltip", "Changes the color this collection should appear as."),
FSlateIcon(),
FUIAction( FExecuteAction::CreateSP( this, &FCollectionContextMenu::ExecutePickColor ) )
);
// Clear Color (only required if any of the selection has one)
if ( SelectedHasCustomColors() )
{
MenuBuilder.AddMenuEntry(
LOCTEXT("ClearColor", "Clear Color"),
LOCTEXT("ClearCollectionColorTooltip", "Resets the color this collection appears as."),
FSlateIcon(),
FUIAction( FExecuteAction::CreateSP( this, &FCollectionContextMenu::ExecuteResetColor ) )
);
}
// Add all the custom colors the user has chosen so far
TArray< FLinearColor > CustomColors;
if ( CollectionViewUtils::HasCustomColors( *CollectionViewPtr->GetCollectionContainer(), &CustomColors ) )
{
MenuBuilder.BeginSection("PathContextCustomColors", LOCTEXT("CustomColorsExistingColors", "Existing Colors") );
{
for ( int32 ColorIndex = 0; ColorIndex < CustomColors.Num(); ColorIndex++ )
{
const FLinearColor& Color = CustomColors[ ColorIndex ];
MenuBuilder.AddWidget(
SNew(SHorizontalBox)
+SHorizontalBox::Slot()
.AutoWidth()
.Padding(2, 0, 0, 0)
[
SNew(SButton)
.ButtonStyle( FAppStyle::Get(), "Menu.Button" )
.OnClicked( this, &FCollectionContextMenu::OnColorClicked, Color )
[
SNew(SColorBlock)
.Color( Color )
.Size( FVector2D(77,16) )
]
],
FText::GetEmpty(),
/*bNoIndent=*/true
);
}
}
MenuBuilder.EndSection();
}
}
void FCollectionContextMenu::UpdateProjectSourceControl()
{
// Force update of source control so that we're always showing the valid options
bCollectionsUnderSourceControl = false;
TSharedPtr<SCollectionView> CollectionViewPtr = CollectionView.Pin();
if (CollectionViewPtr &&
CollectionViewPtr->GetCollectionContainer() &&
ISourceControlModule::Get().IsEnabled() &&
ISourceControlModule::Get().GetProvider().IsAvailable())
{
FString HintFilename = CollectionViewPtr->GetCollectionContainer()->GetCollectionSource()->GetSourceControlStatusHintFilename();
if (!HintFilename.IsEmpty())
{
FSourceControlStatePtr SourceControlState = ISourceControlModule::Get().GetProvider().GetState(HintFilename, EStateCacheUsage::ForceUpdate);
bCollectionsUnderSourceControl = (SourceControlState->IsSourceControlled() && !SourceControlState->IsIgnored() && !SourceControlState->IsUnknown());
}
}
}
bool FCollectionContextMenu::CanRenameSelectedCollections() const
{
TSharedPtr<SCollectionView> CollectionViewPtr = CollectionView.Pin();
if (!CollectionViewPtr.IsValid())
{
return false;
}
if (!CollectionViewPtr->GetCollectionContainer().IsValid())
{
return false;
}
TArray<TSharedPtr<FCollectionItem>> SelectedCollections = CollectionViewPtr->CollectionTreePtr->GetSelectedItems();
if(SelectedCollections.Num() == 1)
{
if (CollectionViewPtr->GetCollectionContainer()->IsReadOnly(SelectedCollections[0]->CollectionType))
{
return false;
}
return !(SelectedCollections[0]->CollectionType != ECollectionShareType::CST_Local) || (bCollectionsUnderSourceControl && ISourceControlModule::Get().IsEnabled() && ISourceControlModule::Get().GetProvider().IsAvailable());
}
return false;
}
void FCollectionContextMenu::ExecuteNewCollection(ECollectionShareType::Type CollectionType, ECollectionStorageMode::Type StorageMode, SCollectionView::FCreateCollectionPayload InCreationPayload)
{
if ( !ensure(CollectionView.IsValid()) )
{
return;
}
const double BeginTimeSec = FPlatformTime::Seconds();
CollectionView.Pin()->CreateCollectionItem(CollectionType, StorageMode, InCreationPayload);
// Telemetry Event
{
FCollectionCreatedTelemetryEvent AssetAdded;
AssetAdded.DurationSec = FPlatformTime::Seconds() - BeginTimeSec;
AssetAdded.CollectionShareType = CollectionType;
FTelemetryRouter::Get().ProvideTelemetry(AssetAdded);
}
}
void FCollectionContextMenu::ExecuteSetCollectionShareType(ECollectionShareType::Type CollectionType)
{
TSharedPtr<SCollectionView> CollectionViewPtr = CollectionView.Pin();
if ( !ensure(CollectionViewPtr.IsValid()) )
{
return;
}
TArray<TSharedPtr<FCollectionItem>> SelectedCollections = CollectionViewPtr->CollectionTreePtr->GetSelectedItems();
if ( !ensure(SelectedCollections.Num() == 1) )
{
return;
}
TSharedPtr<ICollectionContainer> CollectionContainer = CollectionViewPtr->GetCollectionContainer();
CollectionContainer->RenameCollection(SelectedCollections[0]->CollectionName, SelectedCollections[0]->CollectionType, SelectedCollections[0]->CollectionName, CollectionType);
}
void FCollectionContextMenu::ExecuteSaveDynamicCollection(FCollectionNameType InCollection, FText InSearchQuery)
{
TSharedPtr<SCollectionView> CollectionViewPtr = CollectionView.Pin();
if (!ensure(CollectionViewPtr.IsValid()))
{
return;
}
CollectionViewPtr->GetCollectionContainer()->SetDynamicQueryText(InCollection.Name, InCollection.Type, InSearchQuery.ToString());
}
void FCollectionContextMenu::ExecuteRenameCollection()
{
if ( !ensure(CollectionView.IsValid()) )
{
return;
}
TArray<TSharedPtr<FCollectionItem>> SelectedCollections = CollectionView.Pin()->CollectionTreePtr->GetSelectedItems();
if ( !ensure(SelectedCollections.Num() == 1) )
{
return;
}
CollectionView.Pin()->RenameCollectionItem(SelectedCollections[0]);
}
void FCollectionContextMenu::ExecuteUpdateCollection()
{
TSharedPtr<SCollectionView> CollectionViewPtr = CollectionView.Pin();
if ( !ensure(CollectionViewPtr.IsValid()) )
{
return;
}
TSharedPtr<ICollectionContainer> CollectionContainer = CollectionViewPtr->GetCollectionContainer();
TArray<TSharedPtr<FCollectionItem>> SelectedCollections = CollectionViewPtr->CollectionTreePtr->GetSelectedItems();
for (const auto& SelectedCollection : SelectedCollections)
{
if (!CollectionContainer->IsReadOnly(SelectedCollection->CollectionType))
{
CollectionContainer->UpdateCollection(SelectedCollection->CollectionName, SelectedCollection->CollectionType);
}
}
}
void FCollectionContextMenu::ExecuteRefreshCollection()
{
TSharedPtr<SCollectionView> CollectionViewPtr = CollectionView.Pin();
if ( !ensure(CollectionViewPtr.IsValid()) )
{
return;
}
ISourceControlProvider& SourceControlProvider = ISourceControlModule::Get().GetProvider();
TSharedPtr<ICollectionContainer> CollectionContainer = CollectionViewPtr->GetCollectionContainer();
TArray<TSharedPtr<FCollectionItem>> SelectedCollections = CollectionViewPtr->CollectionTreePtr->GetSelectedItems();
TArray<FString> CollectionFilesToRefresh;
for (const auto& SelectedCollection : SelectedCollections)
{
FCollectionStatusInfo StatusInfo;
if (CollectionContainer->GetCollectionStatusInfo(SelectedCollection->CollectionName, SelectedCollection->CollectionType, StatusInfo))
{
if (StatusInfo.bUseSCC && StatusInfo.SCCState.IsValid() && StatusInfo.SCCState->IsSourceControlled())
{
// Forcing a status update will refresh the collection state
SourceControlProvider.GetState(StatusInfo.SCCState->GetFilename(), EStateCacheUsage::ForceUpdate);
}
}
}
}
void FCollectionContextMenu::ExecuteSaveCollection()
{
TSharedPtr<SCollectionView> CollectionViewPtr = CollectionView.Pin();
if ( !ensure(CollectionViewPtr.IsValid()) )
{
return;
}
TSharedPtr<ICollectionContainer> CollectionContainer = CollectionViewPtr->GetCollectionContainer();
TArray<TSharedPtr<FCollectionItem>> SelectedCollections = CollectionViewPtr->CollectionTreePtr->GetSelectedItems();
for (const auto& SelectedCollection : SelectedCollections)
{
if (!CollectionContainer->IsReadOnly(SelectedCollection->CollectionType))
{
CollectionContainer->SaveCollection(SelectedCollection->CollectionName, SelectedCollection->CollectionType);
}
}
}
void FCollectionContextMenu::ExecuteDestroyCollection()
{
TSharedPtr<SCollectionView> CollectionViewPtr = CollectionView.Pin();
if ( !ensure(CollectionViewPtr.IsValid()) )
{
return;
}
TSharedPtr<ICollectionContainer> CollectionContainer = CollectionViewPtr->GetCollectionContainer();
TArray<TSharedPtr<FCollectionItem>> SelectedCollections = CollectionViewPtr->CollectionTreePtr->GetSelectedItems();
SelectedCollections.RemoveAll([&CollectionContainer](const TSharedPtr<FCollectionItem>& CollectionItem)
{
return CollectionContainer->IsReadOnly(CollectionItem->CollectionType);
});
FText Prompt;
if ( SelectedCollections.Num() == 1 )
{
Prompt = FText::Format(LOCTEXT("CollectionDestroyConfirm_Single", "Delete {0}?"), FText::FromName(SelectedCollections[0]->CollectionName));
}
else
{
Prompt = FText::Format(LOCTEXT("CollectionDestroyConfirm_Multiple", "Delete {0} Collections?"), FText::AsNumber(SelectedCollections.Num()));
}
FOnClicked OnYesClicked = FOnClicked::CreateSP( this, &FCollectionContextMenu::ExecuteDestroyCollectionConfirmed, SelectedCollections );
ContentBrowserUtils::DisplayConfirmationPopup(
Prompt,
LOCTEXT("CollectionDestroyConfirm_Yes", "Delete"),
LOCTEXT("CollectionDestroyConfirm_No", "Cancel"),
CollectionView.Pin().ToSharedRef(),
OnYesClicked);
}
FReply FCollectionContextMenu::ExecuteDestroyCollectionConfirmed(TArray<TSharedPtr<FCollectionItem>> CollectionList)
{
const double BeginEventSec = FPlatformTime::Seconds();
CollectionView.Pin()->DeleteCollectionItems(CollectionList);
{
FCollectionsDeletedTelemetryEvent CollectionDeleted;
CollectionDeleted.DurationSec = FPlatformTime::Seconds() - BeginEventSec;
CollectionDeleted.CollectionsDeleted = CollectionList.Num();
FTelemetryRouter::Get().ProvideTelemetry(CollectionDeleted);
}
return FReply::Handled();
}
void FCollectionContextMenu::ExecuteResetColor()
{
ResetColors();
}
void FCollectionContextMenu::ExecutePickColor()
{
TSharedPtr<SCollectionView> CollectionViewPtr = CollectionView.Pin();
TArray<FCollectionNameType> SelectedCollections = CollectionViewPtr->GetSelectedCollections();
FLinearColor InitialColor = FLinearColor::White;
for (const FCollectionNameType& SelectedCollection : SelectedCollections)
{
if (!CollectionViewPtr->GetCollectionContainer()->IsReadOnly(SelectedCollection.Type))
{
InitialColor = CollectionViewUtils::ResolveColor(*CollectionViewPtr->GetCollectionContainer(), SelectedCollection.Name, SelectedCollection.Type);
}
}
FColorPickerArgs PickerArgs;
PickerArgs.bIsModal = true; // TODO: Allow live color updates via a proxy?
PickerArgs.ParentWidget = CollectionViewPtr;
PickerArgs.InitialColor = InitialColor;
PickerArgs.OnColorCommitted.BindSP(this, &FCollectionContextMenu::OnColorCommitted);
OpenColorPicker(PickerArgs);
}
bool FCollectionContextMenu::CanExecuteNewCollection(ECollectionShareType::Type CollectionType, bool bIsValidChildType) const
{
TSharedPtr<SCollectionView> CollectionViewPtr = CollectionView.Pin();
if (!CollectionViewPtr.IsValid())
{
return false;
}
if (!CollectionViewPtr->GetCollectionContainer().IsValid() || CollectionViewPtr->GetCollectionContainer()->IsReadOnly(CollectionType))
{
return false;
}
return bIsValidChildType && (CollectionType == ECollectionShareType::CST_Local || (bCollectionsUnderSourceControl && ISourceControlModule::Get().IsEnabled() && ISourceControlModule::Get().GetProvider().IsAvailable()));
}
bool FCollectionContextMenu::CanExecuteSetCollectionShareType(ECollectionShareType::Type CollectionType) const
{
TSharedPtr<SCollectionView> CollectionViewPtr = CollectionView.Pin();
if ( !ensure(CollectionViewPtr.IsValid()) )
{
return false;
}
if (!CollectionViewPtr->GetCollectionContainer().IsValid() || CollectionViewPtr->GetCollectionContainer()->IsReadOnly(CollectionType))
{
return false;
}
TArray<TSharedPtr<FCollectionItem>> SelectedCollections = CollectionViewPtr->CollectionTreePtr->GetSelectedItems();
if ( !ensure(SelectedCollections.Num() == 1) )
{
return false;
}
if (CollectionViewPtr->GetCollectionContainer()->IsReadOnly(SelectedCollections[0]->CollectionType))
{
return false;
}
const bool bIsSourceControlAvailable = bCollectionsUnderSourceControl && ISourceControlModule::Get().IsEnabled() && ISourceControlModule::Get().GetProvider().IsAvailable();
const bool bIsCurrentTypeLocal = SelectedCollections[0]->CollectionType == ECollectionShareType::CST_Local;
const bool bIsNewTypeLocal = CollectionType == ECollectionShareType::CST_Local;
const bool bIsNewShareTypeDifferent = SelectedCollections[0]->CollectionType != CollectionType;
return bIsNewShareTypeDifferent && ((bIsCurrentTypeLocal && bIsNewTypeLocal) || bIsSourceControlAvailable);
}
bool FCollectionContextMenu::IsSetCollectionShareTypeChecked(ECollectionShareType::Type CollectionType) const
{
if ( !ensure(CollectionView.IsValid()) )
{
return false;
}
TArray<TSharedPtr<FCollectionItem>> SelectedCollections = CollectionView.Pin()->CollectionTreePtr->GetSelectedItems();
if ( !ensure(SelectedCollections.Num() == 1) )
{
return false;
}
return SelectedCollections[0]->CollectionType == CollectionType;
}
bool FCollectionContextMenu::CanExecuteSaveDynamicCollection(FCollectionNameType InCollection) const
{
TSharedPtr<SCollectionView> CollectionViewPtr = CollectionView.Pin();
if (!CollectionViewPtr.IsValid())
{
return false;
}
if (!CollectionViewPtr->GetCollectionContainer().IsValid() || CollectionViewPtr->GetCollectionContainer()->IsReadOnly(InCollection.Type))
{
return false;
}
return InCollection.Type == ECollectionShareType::CST_Local || (bCollectionsUnderSourceControl && ISourceControlModule::Get().IsEnabled() && ISourceControlModule::Get().GetProvider().IsAvailable());
}
bool FCollectionContextMenu::CanExecuteRenameCollection() const
{
return CanRenameSelectedCollections();
}
bool FCollectionContextMenu::CanExecuteDestroyCollection(bool bAnyManagedBySCC, bool bAnyWritable) const
{
TSharedPtr<SCollectionView> CollectionViewPtr = CollectionView.Pin();
if (!CollectionViewPtr.IsValid())
{
return false;
}
if (!CollectionViewPtr->GetCollectionContainer().IsValid() || !bAnyWritable)
{
return false;
}
return !bAnyManagedBySCC || (bCollectionsUnderSourceControl && ISourceControlModule::Get().IsEnabled() && ISourceControlModule::Get().GetProvider().IsAvailable());
}
bool FCollectionContextMenu::SelectedHasCustomColors() const
{
TSharedPtr<SCollectionView> CollectionViewPtr = CollectionView.Pin();
TArray<FCollectionNameType> SelectedCollections = CollectionViewPtr->GetSelectedCollections();
for(const FCollectionNameType& SelectedCollection : SelectedCollections)
{
// Ignore any that are the default color
const TOptional<FLinearColor> Color = CollectionViewUtils::GetCustomColor(CollectionViewPtr->GetCollectionContainer().Get(), SelectedCollection.Name, SelectedCollection.Type);
if (Color)
{
return true;
}
}
return false;
}
bool FCollectionContextMenu::CanExecuteColorChange() const
{
TSharedPtr<SCollectionView> CollectionViewPtr = CollectionView.Pin();
if (!CollectionViewPtr.IsValid())
{
return false;
}
if (!CollectionViewPtr->GetCollectionContainer().IsValid())
{
return false;
}
TArray<TSharedPtr<FCollectionItem>> SelectedCollections = CollectionViewPtr->CollectionTreePtr->GetSelectedItems();
const bool bIsSourceControlValid = bCollectionsUnderSourceControl && ISourceControlModule::Get().IsEnabled() && ISourceControlModule::Get().GetProvider().IsAvailable();
for (TSharedPtr<FCollectionItem> SelectedCollection : SelectedCollections)
{
if (CollectionViewPtr->GetCollectionContainer()->IsReadOnly(SelectedCollection->CollectionType))
{
continue;
}
if (SelectedCollection->CollectionType != ECollectionShareType::CST_Local && !bIsSourceControlValid)
{
continue;
}
return true;
}
return false;
}
FReply FCollectionContextMenu::OnColorClicked( const FLinearColor InColor )
{
OnColorCommitted(InColor);
// Dismiss the menu here, as we can't make the 'clear' option appear if a folder has just had a color set for the first time
FSlateApplication::Get().DismissAllMenus();
return FReply::Handled();
}
void FCollectionContextMenu::OnColorCommitted( const FLinearColor InColor )
{
TSharedPtr<SCollectionView> CollectionViewPtr = CollectionView.Pin();
TArray<FCollectionNameType> SelectedCollections = CollectionViewPtr->GetSelectedCollections();
// Make sure an color entry exists for all the collections, otherwise it can't save correctly
for (const FCollectionNameType& SelectedCollection : SelectedCollections)
{
if (!CollectionViewPtr->GetCollectionContainer()->IsReadOnly(SelectedCollection.Type))
{
CollectionViewUtils::SetCustomColor(*CollectionViewPtr->GetCollectionContainer(), SelectedCollection.Name, SelectedCollection.Type, InColor);
}
}
}
void FCollectionContextMenu::ResetColors()
{
TSharedPtr<SCollectionView> CollectionViewPtr = CollectionView.Pin();
TArray<FCollectionNameType> SelectedCollections = CollectionViewPtr->GetSelectedCollections();
// Clear the custom colors for all the selected collections
for(const FCollectionNameType& SelectedCollection : SelectedCollections)
{
if (!CollectionViewPtr->GetCollectionContainer()->IsReadOnly(SelectedCollection.Type))
{
CollectionViewUtils::SetCustomColor(*CollectionViewPtr->GetCollectionContainer(), SelectedCollection.Name, SelectedCollection.Type, TOptional<FLinearColor>());
}
}
}
#undef LOCTEXT_NAMESPACE