Files
UnrealEngineUWP/Engine/Source/Editor/WorldBrowser/Private/LevelCollectionModel.cpp

1837 lines
50 KiB
C++
Raw Normal View History

// Copyright 1998-2015 Epic Games, Inc. All Rights Reserved.
#include "WorldBrowserPrivatePCH.h"
#include "SourceControlWindows.h"
#include "AssetToolsModule.h"
#include "EditorSupportDelegates.h"
#include "Matinee/MatineeActor.h"
#include "LevelCollectionModel.h"
#include "ShaderCompiler.h"
#include "Engine/LevelStreaming.h"
#include "Engine/Selection.h"
#define LOCTEXT_NAMESPACE "WorldBrowser"
FLevelCollectionModel::FLevelCollectionModel(UEditorEngine* InEditor)
: Editor(InEditor)
, bRequestedUpdateAllLevels(false)
, bRequestedRedrawAllLevels(false)
, bRequestedUpdateActorsCount(false)
, CommandList(MakeShareable(new FUICommandList))
, Filters(MakeShareable(new LevelFilterCollection))
, WorldSize(FIntPoint::ZeroValue)
, bDisplayPaths(false)
, bCanExecuteSCCCheckOut(false)
, bCanExecuteSCCOpenForAdd(false)
, bCanExecuteSCCCheckIn(false)
, bCanExecuteSCC(false)
, bSelectionHasChanged(true)
, bUpdatingLevelsSelection(false)
{
}
FLevelCollectionModel::~FLevelCollectionModel()
{
SaveSettings();
Filters->OnChanged().RemoveAll(this);
FWorldDelegates::LevelAddedToWorld.RemoveAll(this);
FWorldDelegates::LevelRemovedFromWorld.RemoveAll(this);
FEditorSupportDelegates::RedrawAllViewports.RemoveAll(this);
Editor->OnLevelActorAdded().RemoveAll(this);
Editor->OnLevelActorDeleted().RemoveAll(this);
if (CurrentWorld.IsValid())
{
CurrentWorld->OnSelectedLevelsChanged().RemoveAll(this);
}
}
void FLevelCollectionModel::Initialize(UWorld* InWorld)
{
LoadSettings();
CurrentWorld = InWorld;
Filters->OnChanged().AddSP(this, &FLevelCollectionModel::OnFilterChanged);
FWorldDelegates::LevelAddedToWorld.AddSP(this, &FLevelCollectionModel::OnLevelAddedToWorld);
FWorldDelegates::LevelRemovedFromWorld.AddSP(this, &FLevelCollectionModel::OnLevelRemovedFromWorld);
FEditorSupportDelegates::RedrawAllViewports.AddSP(this, &FLevelCollectionModel::OnRedrawAllViewports);
Editor->OnLevelActorAdded().AddSP( this, &FLevelCollectionModel::OnLevelActorAdded);
Editor->OnLevelActorDeleted().AddSP( this, &FLevelCollectionModel::OnLevelActorDeleted);
USelection::SelectionChangedEvent.AddSP(this, &FLevelCollectionModel::OnActorSelectionChanged);
SelectionChanged.AddSP(this, &FLevelCollectionModel::OnActorOrLevelSelectionChanged);
CurrentWorld->OnSelectedLevelsChanged().AddSP(this, &FLevelCollectionModel::OnLevelsSelectionChangedOutside);
PopulateLevelsList();
}
void FLevelCollectionModel::BindCommands()
{
const FLevelCollectionCommands& Commands = FLevelCollectionCommands::Get();
FUICommandList& ActionList = *CommandList;
ActionList.MapAction(Commands.RefreshBrowser,
FExecuteAction::CreateSP(this, &FLevelCollectionModel::RefreshBrowser_Executed));
ActionList.MapAction(Commands.ExpandSelectedItems,
FExecuteAction::CreateSP(this, &FLevelCollectionModel::ExpandSelectedItems_Executed),
FCanExecuteAction::CreateSP(this, &FLevelCollectionModel::AreAnyLevelsSelected));
ActionList.MapAction(Commands.World_MakeLevelCurrent,
FExecuteAction::CreateSP(this, &FLevelCollectionModel::MakeLevelCurrent_Executed),
FCanExecuteAction::CreateSP(this, &FLevelCollectionModel::IsOneLevelSelected));
ActionList.MapAction(Commands.MoveActorsToSelected,
FExecuteAction::CreateSP(this, &FLevelCollectionModel::MoveActorsToSelected_Executed),
FCanExecuteAction::CreateSP(this, &FLevelCollectionModel::IsValidMoveActorsToLevel));
ActionList.MapAction(Commands.MoveFoliageToSelected,
FExecuteAction::CreateSP(this, &FLevelCollectionModel::MoveFoliageToSelected_Executed),
FCanExecuteAction::CreateSP(this, &FLevelCollectionModel::IsValidMoveFoliageToLevel));
ActionList.MapAction(Commands.World_SaveSelectedLevels,
FExecuteAction::CreateSP(this, &FLevelCollectionModel::SaveSelectedLevels_Executed),
FCanExecuteAction::CreateSP(this, &FLevelCollectionModel::AreAnySelectedLevelsDirty));
ActionList.MapAction(Commands.World_SaveSelectedLevelAs,
FExecuteAction::CreateSP(this, &FLevelCollectionModel::SaveSelectedLevelAs_Executed),
FCanExecuteAction::CreateSP(this, &FLevelCollectionModel::IsSelectedLevelEditable));
ActionList.MapAction(Commands.World_LoadLevel,
FExecuteAction::CreateSP(this, &FLevelCollectionModel::LoadSelectedLevels_Executed),
FCanExecuteAction::CreateSP(this, &FLevelCollectionModel::AreAnySelectedLevelsUnloaded));
ActionList.MapAction(Commands.World_UnloadLevel,
FExecuteAction::CreateSP(this, &FLevelCollectionModel::UnloadSelectedLevels_Executed),
FCanExecuteAction::CreateSP(this, &FLevelCollectionModel::AreAnySelectedLevelsLoaded));
ActionList.MapAction( Commands.World_MigrateSelectedLevels,
FExecuteAction::CreateSP( this, &FLevelCollectionModel::MigrateSelectedLevels_Executed),
FCanExecuteAction::CreateSP( this, &FLevelCollectionModel::AreAllSelectedLevelsEditable));
//actors
ActionList.MapAction(Commands.AddsActors,
FExecuteAction::CreateSP(this, &FLevelCollectionModel::SelectActors_Executed),
FCanExecuteAction::CreateSP(this, &FLevelCollectionModel::AreAnySelectedLevelsEditable));
ActionList.MapAction(Commands.RemovesActors,
FExecuteAction::CreateSP(this, &FLevelCollectionModel::DeselectActors_Executed),
FCanExecuteAction::CreateSP(this, &FLevelCollectionModel::AreAnySelectedLevelsEditable));
//visibility
ActionList.MapAction( Commands.World_ShowSelectedLevels,
FExecuteAction::CreateSP( this, &FLevelCollectionModel::ShowSelectedLevels_Executed ),
FCanExecuteAction::CreateSP( this, &FLevelCollectionModel::AreAnySelectedLevelsLoaded ) );
ActionList.MapAction( Commands.World_HideSelectedLevels,
FExecuteAction::CreateSP( this, &FLevelCollectionModel::HideSelectedLevels_Executed ),
FCanExecuteAction::CreateSP( this, &FLevelCollectionModel::AreAnySelectedLevelsLoaded ) );
ActionList.MapAction( Commands.World_ShowOnlySelectedLevels,
FExecuteAction::CreateSP( this, &FLevelCollectionModel::ShowOnlySelectedLevels_Executed ),
FCanExecuteAction::CreateSP( this, &FLevelCollectionModel::AreAnySelectedLevelsLoaded ) );
ActionList.MapAction(Commands.World_ShowAllLevels,
FExecuteAction::CreateSP(this, &FLevelCollectionModel::ShowAllLevels_Executed));
ActionList.MapAction(Commands.World_HideAllLevels,
FExecuteAction::CreateSP(this, &FLevelCollectionModel::HideAllLevels_Executed));
//lock
ActionList.MapAction( Commands.World_LockSelectedLevels,
FExecuteAction::CreateSP( this, &FLevelCollectionModel::LockSelectedLevels_Executed ),
FCanExecuteAction::CreateSP( this, &FLevelCollectionModel::AreAnySelectedLevelsEditable ) );
ActionList.MapAction( Commands.World_UnockSelectedLevels,
FExecuteAction::CreateSP( this, &FLevelCollectionModel::UnockSelectedLevels_Executed ),
FCanExecuteAction::CreateSP( this, &FLevelCollectionModel::AreAnySelectedLevelsEditable ) );
ActionList.MapAction( Commands.World_LockAllLevels,
FExecuteAction::CreateSP( this, &FLevelCollectionModel::LockAllLevels_Executed ) );
ActionList.MapAction( Commands.World_UnockAllLevels,
FExecuteAction::CreateSP( this, &FLevelCollectionModel::UnockAllLevels_Executed ) );
ActionList.MapAction( Commands.World_LockReadOnlyLevels,
FExecuteAction::CreateSP( this, &FLevelCollectionModel::ToggleReadOnlyLevels_Executed ) );
ActionList.MapAction( Commands.World_UnlockReadOnlyLevels,
FExecuteAction::CreateSP( this, &FLevelCollectionModel::ToggleReadOnlyLevels_Executed ) );
//level selection
ActionList.MapAction( Commands.SelectAllLevels,
FExecuteAction::CreateSP( this, &FLevelCollectionModel::SelectAllLevels_Executed ) );
ActionList.MapAction( Commands.DeselectAllLevels,
FExecuteAction::CreateSP( this, &FLevelCollectionModel::DeselectAllLevels_Executed ) );
ActionList.MapAction( Commands.InvertLevelSelection,
FExecuteAction::CreateSP( this, &FLevelCollectionModel::InvertSelection_Executed ) );
//source control
ActionList.MapAction( Commands.SCCCheckOut,
FExecuteAction::CreateSP( this, &FLevelCollectionModel::OnSCCCheckOut ) );
ActionList.MapAction( Commands.SCCCheckIn,
FExecuteAction::CreateSP( this, &FLevelCollectionModel::OnSCCCheckIn ) );
ActionList.MapAction( Commands.SCCOpenForAdd,
FExecuteAction::CreateSP( this, &FLevelCollectionModel::OnSCCOpenForAdd ) );
ActionList.MapAction( Commands.SCCHistory,
FExecuteAction::CreateSP( this, &FLevelCollectionModel::OnSCCHistory ) );
ActionList.MapAction( Commands.SCCRefresh,
FExecuteAction::CreateSP( this, &FLevelCollectionModel::OnSCCRefresh ) );
ActionList.MapAction( Commands.SCCDiffAgainstDepot,
FExecuteAction::CreateSP( this, &FLevelCollectionModel::OnSCCDiffAgainstDepot ) );
ActionList.MapAction( Commands.SCCConnect,
FExecuteAction::CreateSP( this, &FLevelCollectionModel::OnSCCConnect ) );
}
void FLevelCollectionModel::PopulateLevelsList()
{
RootLevelsList.Empty();
AllLevelsList.Empty();
FilteredLevelsList.Empty();
SelectedLevelsList.Empty();
AllLevelsMap.Empty();
OnLevelsCollectionChanged();
}
void FLevelCollectionModel::PopulateFilteredLevelsList()
{
FilteredLevelsList.Empty();
// Filter out our flat list
for (auto& LevelModel : AllLevelsList)
{
LevelModel->SetLevelFilteredOutFlag(true);
if (LevelModel->IsPersistent() || PassesAllFilters(*LevelModel))
{
FilteredLevelsList.Add(LevelModel);
LevelModel->SetLevelFilteredOutFlag(false);
}
}
// Walk through hierarchy and filter it out
for (auto It = RootLevelsList.CreateIterator(); It; ++It)
{
(*It)->OnFilterChanged();
}
}
void FLevelCollectionModel::Tick( float DeltaTime )
{
if (bRequestedUpdateAllLevels)
{
UpdateAllLevels();
}
if (bRequestedRedrawAllLevels)
{
RedrawAllLevels();
}
if (bRequestedUpdateActorsCount)
{
UpdateLevelActorsCount();
}
if (IsSimulating())
{
// Reset simulation status for all levels
for (TSharedPtr<FLevelModel>& LevelModel : AllLevelsList)
{
LevelModel->UpdateSimulationStatus(nullptr);
}
// Traverse streaming levels and update simulation status for corresponding level models
for (ULevelStreaming* StreamingLevel : GetSimulationWorld()->StreamingLevels)
{
// Rebuild the original NonPrefixedPackageName so we can find it
const FString PrefixedPackageName = StreamingLevel->GetWorldAssetPackageName();
const FString NonPrefixedPackageName = FPackageName::GetLongPackagePath(PrefixedPackageName) + "/"
+ FPackageName::GetLongPackageAssetName(PrefixedPackageName).RightChop(GetSimulationWorld()->StreamingLevelsPrefix.Len());
TSharedPtr<FLevelModel> LevelModel = FindLevelModel(FName(*NonPrefixedPackageName));
if (LevelModel.IsValid())
{
LevelModel->UpdateSimulationStatus(StreamingLevel);
}
}
}
}
TStatId FLevelCollectionModel::GetStatId() const
{
RETURN_QUICK_DECLARE_CYCLE_STAT(FLevelCollectionModel, STATGROUP_Tickables);
}
bool FLevelCollectionModel::IsReadOnly() const
{
// read only in PIE/SIE
return IsSimulating();
}
bool FLevelCollectionModel::IsSimulating() const
{
return (Editor->bIsSimulatingInEditor || Editor->PlayWorld != NULL);
}
FLevelModelList& FLevelCollectionModel::GetRootLevelList()
{
return RootLevelsList;
}
const FLevelModelList& FLevelCollectionModel::GetAllLevels() const
{
return AllLevelsList;
}
const FLevelModelList& FLevelCollectionModel::GetFilteredLevels() const
{
return FilteredLevelsList;
}
const FLevelModelList& FLevelCollectionModel::GetSelectedLevels() const
{
return SelectedLevelsList;
}
void FLevelCollectionModel::AddFilter(const TSharedRef<LevelFilter>& InFilter)
{
Filters->Add(InFilter);
OnFilterChanged();
}
void FLevelCollectionModel::RemoveFilter(const TSharedRef<LevelFilter>& InFilter)
{
Filters->Remove(InFilter);
OnFilterChanged();
}
bool FLevelCollectionModel::IsFilterActive() const
{
return (AllLevelsList.Num() != FilteredLevelsList.Num());
}
void FLevelCollectionModel::SetSelectedLevels(const FLevelModelList& InList)
{
// Clear selection flag from currently selected levels
for (auto LevelModel : SelectedLevelsList)
{
LevelModel->SetLevelSelectionFlag(false);
}
SelectedLevelsList.Empty();
// Set selection flag to selected levels
for (auto& LevelModel : InList)
{
if (LevelModel.IsValid() && PassesAllFilters(*LevelModel))
{
LevelModel->SetLevelSelectionFlag(true);
SelectedLevelsList.Add(LevelModel);
}
}
OnLevelsSelectionChanged();
}
void FLevelCollectionModel::SetSelectedLevelsFromWorld()
{
TArray<ULevel*>& SelectedLevelObjects = CurrentWorld->GetSelectedLevels();
FLevelModelList LevelsToSelect;
for (ULevel* LevelObject : SelectedLevelObjects)
{
TSharedPtr<FLevelModel> LevelModel = FindLevelModel(LevelObject);
if (LevelModel.IsValid())
{
LevelsToSelect.Add(LevelModel);
}
}
SetSelectedLevels(LevelsToSelect);
}
TSharedPtr<FLevelModel> FLevelCollectionModel::FindLevelModel(ULevel* InLevel) const
{
if (InLevel)
{
for (auto It = AllLevelsList.CreateConstIterator(); It; ++It)
{
if ((*It)->GetLevelObject() == InLevel)
{
return (*It);
}
}
}
// not found
return TSharedPtr<FLevelModel>();
}
TSharedPtr<FLevelModel> FLevelCollectionModel::FindLevelModel(const FName& PackageName) const
{
const TSharedPtr<FLevelModel>* LevelModel = AllLevelsMap.Find(PackageName);
if (LevelModel != NULL)
{
return *LevelModel;
}
// not found
return TSharedPtr<FLevelModel>();
}
void FLevelCollectionModel::IterateHierarchy(FLevelModelVisitor& Visitor)
{
for (auto It = RootLevelsList.CreateIterator(); It; ++It)
{
(*It)->Accept(Visitor);
}
}
void FLevelCollectionModel::HideLevels(const FLevelModelList& InLevelList)
{
if (IsReadOnly())
{
return;
}
for (auto It = InLevelList.CreateConstIterator(); It; ++It)
{
(*It)->SetVisible(false);
}
RequestUpdateAllLevels();
}
void FLevelCollectionModel::ShowLevels(const FLevelModelList& InLevelList)
{
if (IsReadOnly())
{
return;
}
OnPreShowLevels(InLevelList);
for (auto It = InLevelList.CreateConstIterator(); It; ++It)
{
(*It)->SetVisible(true);
}
RequestUpdateAllLevels();
}
void FLevelCollectionModel::UnlockLevels(const FLevelModelList& InLevelList)
{
if (IsReadOnly())
{
return;
}
for (auto It = InLevelList.CreateConstIterator(); It; ++It)
{
(*It)->SetLocked(false);
}
}
void FLevelCollectionModel::LockLevels(const FLevelModelList& InLevelList)
{
if (IsReadOnly())
{
return;
}
for (auto It = InLevelList.CreateConstIterator(); It; ++It)
{
(*It)->SetLocked(true);
}
}
void FLevelCollectionModel::SaveLevels(const FLevelModelList& InLevelList)
{
if (IsReadOnly())
{
return;
}
FLevelModelList LevelModelsToSave;
TArray<ULevel*> LevelsToSave;
for (auto It = InLevelList.CreateConstIterator(); It; ++It)
{
if ((*It)->GetLevelObject())
{
if (!(*It)->IsVisible())
{
FMessageDialog::Open( EAppMsgType::Ok, NSLOCTEXT("UnrealEd", "UnableToSaveInvisibleLevels", "Save aborted. Levels must be made visible before they can be saved.") );
return;
}
else if ((*It)->IsLocked())
{
FMessageDialog::Open( EAppMsgType::Ok, NSLOCTEXT("UnrealEd", "UnableToSaveLockedLevels", "Save aborted. Level must be unlocked before it can be saved.") );
return;
}
LevelModelsToSave.Add(*It);
LevelsToSave.Add((*It)->GetLevelObject());
}
}
TArray< UPackage* > PackagesNotNeedingCheckout;
// Prompt the user to check out the levels from source control before saving
if (FEditorFileUtils::PromptToCheckoutLevels(false, LevelsToSave, &PackagesNotNeedingCheckout))
{
for (auto It = LevelsToSave.CreateIterator(); It; ++It)
{
FEditorFileUtils::SaveLevel(*It);
}
}
else if (PackagesNotNeedingCheckout.Num() > 0)
{
// The user canceled the checkout dialog but some packages didn't need to be checked out in order to save
// For each selected level if the package its in didn't need to be saved, save the level!
for (int32 LevelIdx = 0; LevelIdx < LevelsToSave.Num(); ++LevelIdx)
{
ULevel* Level = LevelsToSave[LevelIdx];
if (PackagesNotNeedingCheckout.Contains(Level->GetOutermost()))
{
FEditorFileUtils::SaveLevel(Level);
}
else
{
//remove it from the list, so that only successfully saved levels are highlighted when saving is complete
LevelModelsToSave.RemoveAt(LevelIdx);
LevelsToSave.RemoveAt(LevelIdx);
}
}
}
// Select tiles that were saved successfully
SetSelectedLevels(LevelModelsToSave);
}
void FLevelCollectionModel::LoadLevels(const FLevelModelList& InLevelList)
{
if (IsReadOnly())
{
return;
}
GWarn->BeginSlowTask(LOCTEXT("LoadWorldTiles", "Loading levels"), true);
OnPreLoadLevels(InLevelList);
int32 LevelIdx = 0;
for (TSharedPtr<FLevelModel> LevelModel : InLevelList)
{
GWarn->StatusUpdate(LevelIdx++, InLevelList.Num(),
FText::Format(LOCTEXT("LoadingWorldTiles", "Loading: {0}..." ), FText::FromString(LevelModel->GetLongPackageName().ToString()))
);
LevelModel->LoadLevel();
}
GWarn->EndSlowTask();
}
void FLevelCollectionModel::UnloadLevels(const FLevelModelList& InLevelList)
{
if (InLevelList.Num() == 0)
{
return;
}
// If matinee is opened, and if it belongs to the level being removed, close it
if (GLevelEditorModeTools().IsModeActive(FBuiltinEditorModes::EM_InterpEdit))
{
TArray<ULevel*> LevelsToRemove = GetLevelObjectList(InLevelList);
const FEdModeInterpEdit* InterpEditMode = (const FEdModeInterpEdit*)GLevelEditorModeTools().GetActiveMode(FBuiltinEditorModes::EM_InterpEdit);
if (InterpEditMode && InterpEditMode->MatineeActor && LevelsToRemove.Contains(InterpEditMode->MatineeActor->GetLevel()))
{
GLevelEditorModeTools().ActivateDefaultMode();
}
}
else if(GLevelEditorModeTools().IsModeActive(FBuiltinEditorModes::EM_Landscape))
{
GLevelEditorModeTools().ActivateDefaultMode();
}
// Remove each level!
// Take a copy of the list rather than using a reference to the selected levels list, as this will be modified in the loop below
const FLevelModelList LevelListCopy = InLevelList;
for (auto It = LevelListCopy.CreateConstIterator(); It; ++It)
{
TSharedPtr<FLevelModel> LevelModel = (*It);
ULevel* Level = LevelModel->GetLevelObject();
if (Level != NULL && !LevelModel->IsPersistent())
{
// Unselect all actors before removing the level
// This avoids crashing in areas that rely on getting a selected actors level. The level will be invalid after its removed.
for (auto ActorIt = Level->Actors.CreateIterator(); ActorIt; ++ActorIt)
{
Editor->SelectActor((*ActorIt), /*bInSelected=*/ false, /*bSelectEvenIfHidden=*/ false);
}
{
FUnmodifiableObject ImmuneWorld(CurrentWorld.Get());
EditorLevelUtils::RemoveLevelFromWorld(Level);
}
}
}
Editor->ResetTransaction( LOCTEXT("RemoveLevelTransReset", "Removing Levels from World") );
// Collect garbage to clear out the destroyed level
CollectGarbage( GARBAGE_COLLECTION_KEEPFLAGS );
PopulateLevelsList();
}
void FLevelCollectionModel::TranslateLevels(const FLevelModelList& InLevels, FVector2D InDelta, bool bSnapDelta)
{
}
FVector2D FLevelCollectionModel::SnapTranslationDelta(const FLevelModelList& InLevelList, FVector2D InTranslationDelta, bool bBoundsSnapping, float InSnappingValue)
{
return InTranslationDelta;
}
void FLevelCollectionModel::UpdateTranslationDelta(const FLevelModelList& InLevelList, FVector2D InTranslationDelta, bool bBoundsSnapping, float InSnappingValue)
{
FLevelModelList EditableLevels;
// Only editable levels could be moved
for (auto It = InLevelList.CreateConstIterator(); It; ++It)
{
if ((*It)->IsEditable())
{
EditableLevels.Add(*It);
}
}
// Snap translation delta
if (InTranslationDelta != FVector2D::ZeroVector)
{
InTranslationDelta = SnapTranslationDelta(EditableLevels, InTranslationDelta, bBoundsSnapping, InSnappingValue);
}
for (auto It = EditableLevels.CreateIterator(); It; ++It)
{
(*It)->SetLevelTranslationDelta(InTranslationDelta);
}
}
void FLevelCollectionModel::AssignParent(const FLevelModelList& InLevels, TSharedPtr<FLevelModel> InParent)
{
// Attach levels to the new parent
for (auto It = InLevels.CreateConstIterator(); It; ++It)
{
(*It)->AttachTo(InParent);
}
OnLevelsHierarchyChanged();
}
void FLevelCollectionModel::AddExistingLevelsFromAssetData(const TArray<FAssetData>& WorldList)
{
}
TSharedPtr<FLevelDragDropOp> FLevelCollectionModel::CreateDragDropOp() const
{
return TSharedPtr<FLevelDragDropOp>();
}
bool FLevelCollectionModel::PassesAllFilters(const FLevelModel& Item) const
{
if (Item.IsPersistent() || Filters->PassesAllFilters(&Item))
{
return true;
}
return false;
}
void FLevelCollectionModel::BuildHierarchyMenu(FMenuBuilder& InMenuBuilder) const
{
}
void FLevelCollectionModel::CustomizeFileMainMenu(FMenuBuilder& InMenuBuilder) const
{
const FLevelCollectionCommands& Commands = FLevelCollectionCommands::Get();
// Cache SCC state
CacheCanExecuteSourceControlVars();
InMenuBuilder.AddSubMenu(
LOCTEXT("SourceControl", "Source Control"),
LOCTEXT("SourceControl_ToolTip", "Source Control Options"),
FNewMenuDelegate::CreateSP(this, &FLevelCollectionModel::FillSourceControlSubMenu));
if (AreAnyLevelsSelected())
{
InMenuBuilder.AddMenuEntry( Commands.World_SaveSelectedLevels );
InMenuBuilder.AddMenuEntry( Commands.World_SaveSelectedLevelAs );
InMenuBuilder.AddMenuEntry( Commands.World_MigrateSelectedLevels );
}
}
bool FLevelCollectionModel::GetPlayerView(FVector& Location, FRotator& Rotation) const
{
return false;
}
bool FLevelCollectionModel::GetObserverView(FVector& Location, FRotator& Rotation) const
{
return false;
}
bool FLevelCollectionModel::CompareLevelsZOrder(TSharedPtr<FLevelModel> InA, TSharedPtr<FLevelModel> InB) const
{
return false;
}
void FLevelCollectionModel::RegisterDetailsCustomization(FPropertyEditorModule& InPropertyModule,
TSharedPtr<IDetailsView> InDetailsView)
{
}
void FLevelCollectionModel::UnregisterDetailsCustomization(FPropertyEditorModule& InPropertyModule,
TSharedPtr<IDetailsView> InDetailsView)
{
}
void FLevelCollectionModel::RequestUpdateAllLevels()
{
bRequestedUpdateAllLevels = true;
}
void FLevelCollectionModel::RequestRedrawAllLevels()
{
bRequestedRedrawAllLevels = true;
}
void FLevelCollectionModel::UpdateAllLevels()
{
bRequestedUpdateAllLevels = false;
for (auto It = AllLevelsList.CreateConstIterator(); It; ++It)
{
(*It)->Update();
}
// Update world size
FBox WorldBounds = GetLevelsBoundingBox(AllLevelsList, false);
WorldSize.X = FMath::RoundToInt(WorldBounds.GetSize().X);
WorldSize.Y = FMath::RoundToInt(WorldBounds.GetSize().Y);
}
void FLevelCollectionModel::RedrawAllLevels()
{
bRequestedRedrawAllLevels = false;
for (auto It = AllLevelsList.CreateConstIterator(); It; ++It)
{
(*It)->UpdateVisuals();
}
}
void FLevelCollectionModel::UpdateLevelActorsCount()
{
for( auto It = AllLevelsList.CreateIterator(); It; ++It )
{
(*It)->UpdateLevelActorsCount();
}
bRequestedUpdateActorsCount = false;
}
bool FLevelCollectionModel::IsOneLevelSelected() const
{
return SelectedLevelsList.Num() == 1;
}
bool FLevelCollectionModel::AreAnyLevelsSelected() const
{
return SelectedLevelsList.Num() > 0;
}
bool FLevelCollectionModel::AreAllSelectedLevelsLoaded() const
{
for (int32 LevelIdx = 0; LevelIdx < SelectedLevelsList.Num(); LevelIdx++)
{
if (SelectedLevelsList[LevelIdx]->IsLoaded() == false)
{
return false;
}
}
return AreAnyLevelsSelected();
}
bool FLevelCollectionModel::AreAnySelectedLevelsLoaded() const
{
return !AreAllSelectedLevelsUnloaded();
}
bool FLevelCollectionModel::AreAllSelectedLevelsUnloaded() const
{
for (int32 LevelIdx = 0; LevelIdx < SelectedLevelsList.Num(); LevelIdx++)
{
if (SelectedLevelsList[LevelIdx]->IsLoaded() == true)
{
return false;
}
}
return true;
}
bool FLevelCollectionModel::AreAnySelectedLevelsUnloaded() const
{
return !AreAllSelectedLevelsLoaded();
}
bool FLevelCollectionModel::AreAllSelectedLevelsEditable() const
{
for (auto It = SelectedLevelsList.CreateConstIterator(); It; ++It)
{
if ((*It)->IsEditable() == false)
{
return false;
}
}
return AreAnyLevelsSelected();
}
bool FLevelCollectionModel::AreAllSelectedLevelsEditableAndNotPersistent() const
{
for (auto It = SelectedLevelsList.CreateConstIterator(); It; ++It)
{
if ((*It)->IsEditable() == false || (*It)->IsPersistent())
{
return false;
}
}
return AreAnyLevelsSelected();
}
bool FLevelCollectionModel::AreAllSelectedLevelsEditableAndVisible() const
{
for (auto It = SelectedLevelsList.CreateConstIterator(); It; ++It)
{
if ((*It)->IsEditable() == false ||
(*It)->IsVisible() == false)
{
return false;
}
}
return AreAnyLevelsSelected();
}
bool FLevelCollectionModel::AreAnySelectedLevelsEditable() const
{
for (auto It = SelectedLevelsList.CreateConstIterator(); It; ++It)
{
if ((*It)->IsEditable() == true)
{
return true;
}
}
return false;
}
bool FLevelCollectionModel::AreAnySelectedLevelsEditableAndVisible() const
{
for (auto It = SelectedLevelsList.CreateConstIterator(); It; ++It)
{
if ((*It)->IsEditable() == true &&
(*It)->IsVisible() == true)
{
return true;
}
}
return false;
}
bool FLevelCollectionModel::IsSelectedLevelEditable() const
{
if (SelectedLevelsList.Num() == 1)
{
return SelectedLevelsList[0]->IsEditable();
}
return false;
}
bool FLevelCollectionModel::AreAnySelectedLevelsDirty() const
{
for (auto It = SelectedLevelsList.CreateConstIterator(); It; ++It)
{
if ((*It)->IsLoaded() == true && (*It)->IsDirty() == true)
{
return true;
}
}
return false;
}
bool FLevelCollectionModel::AreActorsSelected() const
{
return Editor->GetSelectedActorCount() > 0;
}
bool FLevelCollectionModel::GetDisplayPathsState() const
{
return bDisplayPaths;
}
void FLevelCollectionModel::SetDisplayPathsState(bool InDisplayPaths)
{
bDisplayPaths = InDisplayPaths;
for (auto It = AllLevelsList.CreateIterator(); It; ++It)
{
(*It)->UpdateDisplayName();
}
}
bool FLevelCollectionModel::GetDisplayActorsCountState() const
{
return bDisplayActorsCount;
}
void FLevelCollectionModel::SetDisplayActorsCountState(bool InDisplayActorsCount)
{
bDisplayActorsCount = InDisplayActorsCount;
for (auto It = AllLevelsList.CreateIterator(); It; ++It)
{
(*It)->UpdateDisplayName();
}
}
void FLevelCollectionModel::BroadcastSelectionChanged()
{
SelectionChanged.Broadcast();
}
void FLevelCollectionModel::BroadcastCollectionChanged()
{
CollectionChanged.Broadcast();
}
void FLevelCollectionModel::BroadcastHierarchyChanged()
{
HierarchyChanged.Broadcast();
}
float FLevelCollectionModel::EditableAxisLength()
{
return HALF_WORLD_MAX;
};
FBox FLevelCollectionModel::EditableWorldArea()
{
float AxisLength = EditableAxisLength();
return FBox(
FVector(-AxisLength, -AxisLength, -AxisLength),
FVector(+AxisLength, +AxisLength, +AxisLength)
);
}
void FLevelCollectionModel::SCCCheckOut(const FLevelModelList& InList)
{
TArray<FString> FilenamesToCheckOut = GetFilenamesList(InList);
// Update the source control status of all potentially relevant packages
ISourceControlModule::Get().GetProvider().Execute(
ISourceControlOperation::Create<FUpdateStatus>(), FilenamesToCheckOut
);
// Now check them out
FEditorFileUtils::CheckoutPackages(FilenamesToCheckOut);
}
void FLevelCollectionModel::SCCCheckIn(const FLevelModelList& InList)
{
TArray<UPackage*> PackagesToCheckIn = GetPackagesList(InList);
TArray<FString> FilenamesToCheckIn = GetFilenamesList(InList);
// Prompt the user to ask if they would like to first save any dirty packages they are trying to check-in
const auto UserResponse = FEditorFileUtils::PromptForCheckoutAndSave(PackagesToCheckIn, true, true);
// If the user elected to save dirty packages, but one or more of the packages failed to save properly OR if the user
// canceled out of the prompt, don't follow through on the check-in process
const bool bShouldProceed = UserResponse == FEditorFileUtils::EPromptReturnCode::PR_Success ||
UserResponse == FEditorFileUtils::EPromptReturnCode::PR_Declined;
if (bShouldProceed)
{
const bool bUseSourceControlStateCache = false;
FSourceControlWindows::PromptForCheckin(bUseSourceControlStateCache, FilenamesToCheckIn);
}
else
{
// If a failure occurred, alert the user that the check-in was aborted. This warning shouldn't be necessary if the user cancelled
// from the dialog, because they obviously intended to cancel the whole operation.
if (UserResponse == FEditorFileUtils::EPromptReturnCode::PR_Failure)
{
FMessageDialog::Open(EAppMsgType::Ok,
NSLOCTEXT("UnrealEd", "SCC_Checkin_Aborted", "Check-in aborted as a result of save failure.")
);
}
}
}
void FLevelCollectionModel::SCCOpenForAdd(const FLevelModelList& InList)
{
ISourceControlProvider& SourceControlProvider = ISourceControlModule::Get().GetProvider();
TArray<FString> FilenamesList = GetFilenamesList(InList);
TArray<FString> FilenamesToAdd;
TArray<UPackage*> PackagesToSave;
for (auto It = FilenamesList.CreateConstIterator(); It; ++It)
{
const FSourceControlStatePtr SourceControlState = SourceControlProvider.GetState(*It, EStateCacheUsage::Use);
if (SourceControlState.IsValid() && !SourceControlState->IsSourceControlled())
{
FilenamesToAdd.Add(*It);
// Make sure the file actually exists on disk before adding it
FString LongPackageName = FPackageName::FilenameToLongPackageName(*It);
if (!FPackageName::DoesPackageExist(LongPackageName))
{
UPackage* Package = FindPackage(NULL, *LongPackageName);
if (Package)
{
PackagesToSave.Add(Package);
}
}
}
}
if (FilenamesToAdd.Num() > 0)
{
// If any of the packages are new, save them now
if (PackagesToSave.Num() > 0)
{
const bool bCheckDirty = false;
const bool bPromptToSave = false;
const auto Return = FEditorFileUtils::PromptForCheckoutAndSave(PackagesToSave, bCheckDirty, bPromptToSave);
}
SourceControlProvider.Execute(ISourceControlOperation::Create<FMarkForAdd>(), FilenamesToAdd);
}
}
void FLevelCollectionModel::SCCHistory(const FLevelModelList& InList)
{
// This is odd, why SCC needs package names, instead of filenames?
TArray<FString> PackageNames;
for (auto It = InList.CreateConstIterator(); It; ++It)
{
if ((*It)->HasValidPackage())
{
PackageNames.Add((*It)->GetLongPackageName().ToString());
}
}
FSourceControlWindows::DisplayRevisionHistory(PackageNames);
}
void FLevelCollectionModel::SCCRefresh(const FLevelModelList& InList)
{
if(ISourceControlModule::Get().IsEnabled())
{
ISourceControlModule::Get().QueueStatusUpdate(GetFilenamesList(InList));
}
}
void FLevelCollectionModel::SCCDiffAgainstDepot(const FLevelModelList& InList, UEditorEngine* InEditor)
{
// Load the asset registry module
FAssetToolsModule& AssetToolsModule = FModuleManager::GetModuleChecked<FAssetToolsModule>("AssetTools");
ISourceControlProvider& SourceControlProvider = ISourceControlModule::Get().GetProvider();
// Iterate over each selected asset
for (auto It = InList.CreateConstIterator(); It; ++It)
{
ULevel* Level = (*It)->GetLevelObject();
if (Level == NULL)
{
return;
}
UPackage* OriginalPackage = Level->GetOutermost();
FString PackageName = OriginalPackage->GetName();
// Make sure our history is up to date
auto UpdateStatusOperation = ISourceControlOperation::Create<FUpdateStatus>();
UpdateStatusOperation->SetUpdateHistory(true);
SourceControlProvider.Execute(UpdateStatusOperation, OriginalPackage);
// Get the SCC state
FSourceControlStatePtr SourceControlState = SourceControlProvider.GetState(
OriginalPackage, EStateCacheUsage::Use
);
// If the level is in SCC.
if (SourceControlState.IsValid() && SourceControlState->IsSourceControlled())
{
// Get the file name of package
FString RelativeFileName;
if(FPackageName::DoesPackageExist(PackageName, NULL, &RelativeFileName))
{
if (SourceControlState->GetHistorySize() > 0)
{
auto Revision = SourceControlState->GetHistoryItem(0);
check(Revision.IsValid());
// Get the head revision of this package from source control
FString AbsoluteFileName = FPaths::ConvertRelativePathToFull(RelativeFileName);
FString TempFileName;
if (Revision->Get(TempFileName))
{
// Forcibly disable compile on load in case we are loading old blueprints that might try to update/compile
TGuardValue<bool> DisableCompileOnLoad(GForceDisableBlueprintCompileOnLoad, true);
// Try and load that package
FText NotMapReason;
UPackage* OldPackage = LoadPackage(NULL, *TempFileName, LOAD_None);
if(OldPackage != NULL && InEditor->PackageIsAMapFile(*TempFileName, NotMapReason))
{
/* Set the revision information*/
UPackage* Package = OriginalPackage;
FRevisionInfo OldRevision;
OldRevision.Changelist = Revision->GetCheckInIdentifier();
OldRevision.Date = Revision->GetDate();
OldRevision.Revision = Revision->GetRevision();
FRevisionInfo NewRevision;
NewRevision.Revision = TEXT("");
// Dump assets to temp text files
FString OldTextFilename = AssetToolsModule.Get().DumpAssetToTempFile(OldPackage);
FString NewTextFilename = AssetToolsModule.Get().DumpAssetToTempFile(OriginalPackage);
FString DiffCommand = GetDefault<UEditorLoadingSavingSettings>()->TextDiffToolPath.FilePath;
AssetToolsModule.Get().CreateDiffProcess(DiffCommand, OldTextFilename, NewTextFilename);
AssetToolsModule.Get().DiffAssets(OldPackage, OriginalPackage, OldRevision, NewRevision);
}
}
}
}
}
}
}
TArray<FName> FLevelCollectionModel::GetPackageNamesList(const FLevelModelList& InList)
{
TArray<FName> ResultList;
for (auto It = InList.CreateConstIterator(); It; ++It)
{
if ((*It)->HasValidPackage())
{
ResultList.Add((*It)->GetLongPackageName());
}
}
return ResultList;
}
TArray<FString> FLevelCollectionModel::GetFilenamesList(const FLevelModelList& InList)
{
TArray<FString> ResultList;
for (auto It = InList.CreateConstIterator(); It; ++It)
{
if ((*It)->HasValidPackage())
{
ResultList.Add((*It)->GetPackageFileName());
}
}
return ResultList;
}
TArray<UPackage*> FLevelCollectionModel::GetPackagesList(const FLevelModelList& InList)
{
TArray<UPackage*> ResultList;
for (auto It = InList.CreateConstIterator(); It; ++It)
{
ULevel* Level = (*It)->GetLevelObject();
if (Level)
{
ResultList.Add(Level->GetOutermost());
}
}
return ResultList;
}
TArray<ULevel*> FLevelCollectionModel::GetLevelObjectList(const FLevelModelList& InList)
{
TArray<ULevel*> ResultList;
for (auto It = InList.CreateConstIterator(); It; ++It)
{
ULevel* Level = (*It)->GetLevelObject();
if (Level)
{
ResultList.Add(Level);
}
}
return ResultList;
}
FLevelModelList FLevelCollectionModel::GetLoadedLevels(const FLevelModelList& InList)
{
FLevelModelList ResultList;
for (auto It = InList.CreateConstIterator(); It; ++It)
{
if ((*It)->IsLoaded())
{
ResultList.Add(*It);
}
}
return ResultList;
}
FLevelModelList FLevelCollectionModel::GetLevelsHierarchy(const FLevelModelList& InList)
{
struct FHierarchyCollector : public FLevelModelVisitor
{
virtual void Visit(FLevelModel& Item) override
{
ResultList.AddUnique(Item.AsShared());
}
FLevelModelList ResultList;
};
FHierarchyCollector HierarchyCollector;
for (auto It = InList.CreateConstIterator(); It; ++It)
{
(*It)->Accept(HierarchyCollector);
}
return HierarchyCollector.ResultList;
}
FBox FLevelCollectionModel::GetLevelsBoundingBox(const FLevelModelList& InList, bool bIncludeChildren)
{
FBox TotalBounds(0);
for (auto It = InList.CreateConstIterator(); It; ++It)
{
if (bIncludeChildren)
{
TotalBounds+= GetVisibleLevelsBoundingBox((*It)->GetChildren(), bIncludeChildren);
}
TotalBounds+= (*It)->GetLevelBounds();
}
return TotalBounds;
}
FBox FLevelCollectionModel::GetVisibleLevelsBoundingBox(const FLevelModelList& InList, bool bIncludeChildren)
{
FBox TotalBounds(0);
for (auto It = InList.CreateConstIterator(); It; ++It)
{
if (bIncludeChildren)
{
TotalBounds+= GetVisibleLevelsBoundingBox((*It)->GetChildren(), bIncludeChildren);
}
if ((*It)->IsVisible())
{
TotalBounds+= (*It)->GetLevelBounds();
}
}
return TotalBounds;
}
const TSharedRef<const FUICommandList> FLevelCollectionModel::GetCommandList() const
{
return CommandList;
}
const FString ConfigIniSection = TEXT("WorldBrowser");
void FLevelCollectionModel::LoadSettings()
{
// Display paths
bool bDisplayPathsSetting = false;
GConfig->GetBool(*ConfigIniSection, TEXT("DisplayPaths"), bDisplayPathsSetting, GEditorPerProjectIni);
SetDisplayPathsState(bDisplayPathsSetting);
// Display actors count
bool bDisplayActorsCountSetting = false;
GConfig->GetBool(*ConfigIniSection, TEXT("DisplayActorsCount"), bDisplayActorsCountSetting, GEditorPerProjectIni);
SetDisplayActorsCountState(bDisplayActorsCountSetting);
}
void FLevelCollectionModel::SaveSettings()
{
// Display paths
GConfig->SetBool(*ConfigIniSection, TEXT("DisplayPaths"), GetDisplayPathsState(), GEditorPerProjectIni);
// Display actors count
GConfig->SetBool(*ConfigIniSection, TEXT("DisplayActorsCount"), GetDisplayActorsCountState(), GEditorPerProjectIni);
}
void FLevelCollectionModel::RefreshBrowser_Executed()
{
PopulateLevelsList();
}
void FLevelCollectionModel::LoadSelectedLevels_Executed()
{
LoadLevels(GetSelectedLevels());
}
void FLevelCollectionModel::UnloadSelectedLevels_Executed()
{
UnloadLevels(GetSelectedLevels());
}
void FLevelCollectionModel::OnSCCCheckOut()
{
SCCCheckOut(GetSelectedLevels());
}
void FLevelCollectionModel::OnSCCCheckIn()
{
SCCCheckIn(GetSelectedLevels());
}
void FLevelCollectionModel::OnSCCOpenForAdd()
{
SCCOpenForAdd(GetSelectedLevels());
}
void FLevelCollectionModel::OnSCCHistory()
{
SCCHistory(GetSelectedLevels());
}
void FLevelCollectionModel::OnSCCRefresh()
{
SCCRefresh(GetSelectedLevels());
}
void FLevelCollectionModel::OnSCCDiffAgainstDepot()
{
SCCDiffAgainstDepot(GetSelectedLevels(), Editor.Get());
}
void FLevelCollectionModel::OnSCCConnect() const
{
ISourceControlModule::Get().ShowLoginDialog(FSourceControlLoginClosed(), ELoginWindowMode::Modeless);
}
void FLevelCollectionModel::SaveSelectedLevels_Executed()
{
SaveLevels(GetSelectedLevels());
}
void FLevelCollectionModel::SaveSelectedLevelAs_Executed()
{
if (SelectedLevelsList.Num() > 0)
{
ULevel* Level = SelectedLevelsList[0]->GetLevelObject();
if (Level)
{
FEditorFileUtils::SaveAs(Level);
}
}
}
void FLevelCollectionModel::MigrateSelectedLevels_Executed()
{
// Gather the package names for the levels
TArray<FName> PackageNames = GetPackageNamesList(GetSelectedLevels());
FAssetToolsModule& AssetToolsModule = FModuleManager::Get().LoadModuleChecked<FAssetToolsModule>("AssetTools");
AssetToolsModule.Get().MigratePackages(PackageNames);
}
void FLevelCollectionModel::SelectAllLevels_Executed()
{
SetSelectedLevels(FilteredLevelsList);
}
void FLevelCollectionModel::DeselectAllLevels_Executed()
{
FLevelModelList NoLevels;
SetSelectedLevels(NoLevels);
}
void FLevelCollectionModel::InvertSelection_Executed()
{
FLevelModelList InvertedLevels;
for (auto It = FilteredLevelsList.CreateIterator(); It; ++It)
{
if (!SelectedLevelsList.Contains(*It))
{
InvertedLevels.Add(*It);
}
}
SetSelectedLevels(InvertedLevels);
}
void FLevelCollectionModel::ShowSelectedLevels_Executed()
{
ShowLevels(GetSelectedLevels());
}
void FLevelCollectionModel::HideSelectedLevels_Executed()
{
HideLevels(GetSelectedLevels());
}
void FLevelCollectionModel::ShowOnlySelectedLevels_Executed()
{
//stash off a copy of the original array, as setting visibility can destroy the selection
FLevelModelList SelectedLevelsCopy = GetSelectedLevels();
InvertSelection_Executed();
HideSelectedLevels_Executed();
SetSelectedLevels(SelectedLevelsCopy);
ShowSelectedLevels_Executed();
}
void FLevelCollectionModel::ShowAllLevels_Executed()
{
ShowLevels(GetFilteredLevels());
}
void FLevelCollectionModel::HideAllLevels_Executed()
{
HideLevels(GetFilteredLevels());
}
void FLevelCollectionModel::LockSelectedLevels_Executed()
{
LockLevels(GetSelectedLevels());
}
void FLevelCollectionModel::UnockSelectedLevels_Executed()
{
UnlockLevels(GetSelectedLevels());
}
void FLevelCollectionModel::LockAllLevels_Executed()
{
LockLevels(GetFilteredLevels());
}
void FLevelCollectionModel::UnockAllLevels_Executed()
{
UnlockLevels(GetFilteredLevels());
}
void FLevelCollectionModel::ToggleReadOnlyLevels_Executed()
{
Editor->bLockReadOnlyLevels = !Editor->bLockReadOnlyLevels;
}
void FLevelCollectionModel::MakeLevelCurrent_Executed()
{
check( SelectedLevelsList.Num() == 1 );
SelectedLevelsList[0]->MakeLevelCurrent();
}
void FLevelCollectionModel::MoveActorsToSelected_Executed()
{
// If matinee is open, and if an actor being moved belongs to it, message the user
if (GLevelEditorModeTools().IsModeActive(FBuiltinEditorModes::EM_InterpEdit))
{
const FEdModeInterpEdit* InterpEditMode = (const FEdModeInterpEdit*)GLevelEditorModeTools().GetActiveMode(FBuiltinEditorModes::EM_InterpEdit);
if (InterpEditMode && InterpEditMode->MatineeActor)
{
TArray<AActor*> ControlledActors;
InterpEditMode->MatineeActor->GetControlledActors(ControlledActors);
// are any of the selected actors in the matinee
USelection* SelectedActors = GEditor->GetSelectedActors();
for (FSelectionIterator Iter(*SelectedActors); Iter; ++Iter)
{
AActor* Actor = CastChecked<AActor>(*Iter);
if (Actor != nullptr && (Actor == InterpEditMode->MatineeActor || ControlledActors.Contains(Actor)))
{
const bool ExitInterp = EAppReturnType::Yes == FMessageDialog::Open(EAppMsgType::YesNo, NSLOCTEXT("UnrealEd", "MatineeUnableToMove", "You must close Matinee before moving actors.\nDo you wish to do this now and continue?"));
if (!ExitInterp)
{
return;
}
GLevelEditorModeTools().DeactivateMode(FBuiltinEditorModes::EM_InterpEdit);
break;
}
}
}
}
MakeLevelCurrent_Executed();
const FScopedTransaction Transaction( LOCTEXT("MoveSelectedActorsToSelectedLevel", "Move Selected Actors to Level") );
Editor->MoveSelectedActorsToLevel(GetWorld()->GetCurrentLevel());
RequestUpdateAllLevels();
}
void FLevelCollectionModel::MoveFoliageToSelected_Executed()
{
if (GetSelectedLevels().Num() == 1)
{
ULevel* TargetLevel = GetSelectedLevels()[0]->GetLevelObject();
Editor->MoveSelectedFoliageToLevel(TargetLevel);
}
}
void FLevelCollectionModel::SelectActors_Executed()
{
//first clear any existing actor selection
const FScopedTransaction Transaction( LOCTEXT("SelectActors", "Select Actors in Level") );
Editor->GetSelectedActors()->Modify();
Editor->SelectNone( false, true );
for(auto It = SelectedLevelsList.CreateConstIterator(); It; ++It)
{
(*It)->SelectActors(/*bSelect*/ true, /*bNotify*/ true, /*bSelectEvenIfHidden*/ true);
}
}
void FLevelCollectionModel::DeselectActors_Executed()
{
const FScopedTransaction Transaction( LOCTEXT("DeselectActors", "Deselect Actors in Level") );
for(auto It = SelectedLevelsList.CreateConstIterator(); It; ++It)
{
(*It)->SelectActors(/*bSelect*/ false, /*bNotify*/ true, /*bSelectEvenIfHidden*/ true);
}
}
void FLevelCollectionModel::ExpandSelectedItems_Executed()
{
struct FExpandLevelVisitor : public FLevelModelVisitor
{
virtual void Visit(FLevelModel& Item) override { Item.SetLevelExpansionFlag(true); }
} Expander;
for (TSharedPtr<FLevelModel> LevelModel: SelectedLevelsList)
{
LevelModel->Accept(Expander);
}
BroadcastHierarchyChanged();
}
void FLevelCollectionModel::FillLockSubMenu(FMenuBuilder& InMenuBuilder)
{
const FLevelCollectionCommands& Commands = FLevelCollectionCommands::Get();
InMenuBuilder.AddMenuEntry( Commands.World_LockSelectedLevels );
InMenuBuilder.AddMenuEntry( Commands.World_UnockSelectedLevels );
InMenuBuilder.AddMenuEntry( Commands.World_LockAllLevels );
InMenuBuilder.AddMenuEntry( Commands.World_UnockAllLevels );
if (Editor->bLockReadOnlyLevels)
{
InMenuBuilder.AddMenuEntry( Commands.World_UnlockReadOnlyLevels );
}
else
{
InMenuBuilder.AddMenuEntry( Commands.World_LockReadOnlyLevels );
}
}
void FLevelCollectionModel::FillVisibilitySubMenu(FMenuBuilder& InMenuBuilder)
{
const FLevelCollectionCommands& Commands = FLevelCollectionCommands::Get();
InMenuBuilder.AddMenuEntry( Commands.World_ShowSelectedLevels );
InMenuBuilder.AddMenuEntry( Commands.World_HideSelectedLevels );
InMenuBuilder.AddMenuEntry( Commands.World_ShowOnlySelectedLevels );
InMenuBuilder.AddMenuEntry( Commands.World_ShowAllLevels );
InMenuBuilder.AddMenuEntry( Commands.World_HideAllLevels );
}
void FLevelCollectionModel::FillSourceControlSubMenu(FMenuBuilder& InMenuBuilder)
{
const FLevelCollectionCommands& Commands = FLevelCollectionCommands::Get();
if (CanExecuteSCC())
{
if (CanExecuteSCCCheckOut())
{
InMenuBuilder.AddMenuEntry( Commands.SCCCheckOut );
}
if (CanExecuteSCCOpenForAdd())
{
InMenuBuilder.AddMenuEntry( Commands.SCCOpenForAdd );
}
if (CanExecuteSCCCheckIn())
{
InMenuBuilder.AddMenuEntry( Commands.SCCCheckIn );
}
InMenuBuilder.AddMenuEntry( Commands.SCCRefresh );
InMenuBuilder.AddMenuEntry( Commands.SCCHistory );
InMenuBuilder.AddMenuEntry( Commands.SCCDiffAgainstDepot );
}
else
{
InMenuBuilder.AddMenuEntry( Commands.SCCConnect );
}
}
void FLevelCollectionModel::OnLevelsCollectionChanged()
{
UpdateAllLevels();
PopulateFilteredLevelsList();
BroadcastCollectionChanged();
}
void FLevelCollectionModel::OnLevelsSelectionChanged()
{
if (bUpdatingLevelsSelection)
{
return;
}
TGuardValue<bool> UpdateGuard(bUpdatingLevelsSelection, true);
// Pass the list we just created to the world to set the selection
CurrentWorld->SetSelectedLevels(
GetLevelObjectList(SelectedLevelsList)
);
// Request SC status update for selected levels
ISourceControlModule::Get().QueueStatusUpdate(
GetFilenamesList(SelectedLevelsList)
);
// Expand hierarchy to selected levels
for (auto It = SelectedLevelsList.CreateIterator(); It; ++It)
{
TSharedPtr<FLevelModel> ParentLevelModel = (*It)->GetParent();
while (ParentLevelModel.IsValid())
{
ParentLevelModel->SetLevelExpansionFlag(true);
ParentLevelModel = ParentLevelModel->GetParent();
}
}
BroadcastSelectionChanged();
}
void FLevelCollectionModel::OnLevelsSelectionChangedOutside()
{
if (!bUpdatingLevelsSelection)
{
SetSelectedLevelsFromWorld();
}
}
void FLevelCollectionModel::OnLevelsHierarchyChanged()
{
BroadcastHierarchyChanged();
}
void FLevelCollectionModel::OnLevelAddedToWorld(ULevel* InLevel, UWorld* InWorld)
{
if (InWorld == GetWorld())
{
TSharedPtr<FLevelModel> LevelModel = FindLevelModel(InLevel->GetOutermost()->GetFName());
if (LevelModel.IsValid())
{
LevelModel->OnLevelAddedToWorld(InLevel);
}
}
}
void FLevelCollectionModel::OnLevelRemovedFromWorld(ULevel* InLevel, UWorld* InWorld)
{
if (InWorld == GetWorld())
{
TSharedPtr<FLevelModel> LevelModel = FindLevelModel(InLevel->GetOutermost()->GetFName());
if (LevelModel.IsValid())
{
LevelModel->OnLevelRemovedFromWorld();
}
}
}
void FLevelCollectionModel::OnRedrawAllViewports()
{
if (GShaderCompilingManager && GShaderCompilingManager->IsCompiling())
{
// Editor seems like still compiling shaders, do not request tiles redraw until all shaders complation is finished
// Basically redraw only on last event
return;
}
RequestRedrawAllLevels();
}
void FLevelCollectionModel::OnLevelActorAdded(AActor* InActor)
{
if (InActor &&
InActor->GetWorld() == CurrentWorld.Get()) // we care about our world only
{
bRequestedUpdateActorsCount = true;
}
}
void FLevelCollectionModel::OnLevelActorDeleted(AActor* InActor)
{
bRequestedUpdateActorsCount = true;
}
void FLevelCollectionModel::OnFilterChanged()
{
PopulateFilteredLevelsList();
BroadcastCollectionChanged();
}
void FLevelCollectionModel::CacheCanExecuteSourceControlVars() const
{
bCanExecuteSCCCheckOut = false;
bCanExecuteSCCOpenForAdd = false;
bCanExecuteSCCCheckIn = false;
bCanExecuteSCC = false;
ISourceControlProvider& SourceControlProvider = ISourceControlModule::Get().GetProvider();
for (auto It = SelectedLevelsList.CreateConstIterator(); It; ++It)
{
if (ISourceControlModule::Get().IsEnabled() && SourceControlProvider.IsAvailable())
{
bCanExecuteSCC = true;
ULevel* Level = (*It)->GetLevelObject();
if (Level)
{
// Check the SCC state for each package in the selected paths
FSourceControlStatePtr SourceControlState = SourceControlProvider.GetState(Level->GetOutermost(), EStateCacheUsage::Use);
if (SourceControlState.IsValid())
{
if (SourceControlState->CanCheckout())
{
bCanExecuteSCCCheckOut = true;
}
else if (!SourceControlState->IsSourceControlled())
{
bCanExecuteSCCOpenForAdd = true;
}
else if (SourceControlState->IsCheckedOut() || SourceControlState->IsAdded())
{
bCanExecuteSCCCheckIn = true;
}
}
}
}
if (bCanExecuteSCCCheckOut &&
bCanExecuteSCCOpenForAdd &&
bCanExecuteSCCCheckIn)
{
// All options are available, no need to keep iterating
break;
}
}
}
bool FLevelCollectionModel::IsValidMoveActorsToLevel() const
{
static bool bCachedIsValidActorMoveResult = false;
if (bSelectionHasChanged)
{
bSelectionHasChanged = false;
bCachedIsValidActorMoveResult = false;
// We can only operate on a single selected level
if ( SelectedLevelsList.Num() == 1 )
{
ULevel* Level = SelectedLevelsList[0]->GetLevelObject();
if (Level)
{
// Allow the move if at least one actor is in another level
USelection* SelectedActors = GEditor->GetSelectedActors();
for (FSelectionIterator Iter(*SelectedActors); Iter; ++Iter)
{
AActor* Actor = CastChecked<AActor>(*Iter);
if (Actor != nullptr)
{
if (Actor->GetLevel() != Level)
{
bCachedIsValidActorMoveResult = true;
break;
}
}
}
}
}
}
// if non of the selected actors are in the level, just check the level is unlocked
return bCachedIsValidActorMoveResult && AreAllSelectedLevelsEditableAndVisible();
}
bool FLevelCollectionModel::IsValidMoveFoliageToLevel() const
{
if (IsOneLevelSelected() &&
AreAllSelectedLevelsEditableAndVisible() &&
GLevelEditorModeTools().IsModeActive(FBuiltinEditorModes::EM_Foliage))
{
return true;
}
return false;
}
void FLevelCollectionModel::OnActorSelectionChanged(UObject* obj)
{
OnActorOrLevelSelectionChanged();
}
void FLevelCollectionModel::OnActorOrLevelSelectionChanged()
{
bSelectionHasChanged = true;
}
#undef LOCTEXT_NAMESPACE