You've already forked UnrealEngineUWP
mirror of
https://github.com/izzy2lost/UnrealEngineUWP.git
synced 2026-03-26 18:15:20 -07:00
1839 lines
50 KiB
C++
1839 lines
50 KiB
C++
// 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 It = AllLevelsList.CreateIterator(); It; ++It)
|
|
{
|
|
TSharedPtr<FLevelModel> LevelModel = (*It);
|
|
|
|
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(TSharedPtr<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, GEditorUserSettingsIni);
|
|
SetDisplayPathsState(bDisplayPathsSetting);
|
|
|
|
// Display actors count
|
|
bool bDisplayActorsCountSetting = false;
|
|
GConfig->GetBool(*ConfigIniSection, TEXT("DisplayActorsCount"), bDisplayActorsCountSetting, GEditorUserSettingsIni);
|
|
SetDisplayActorsCountState(bDisplayActorsCountSetting);
|
|
}
|
|
|
|
void FLevelCollectionModel::SaveSettings()
|
|
{
|
|
// Display paths
|
|
GConfig->SetBool(*ConfigIniSection, TEXT("DisplayPaths"), GetDisplayPathsState(), GEditorUserSettingsIni);
|
|
|
|
// Display actors count
|
|
GConfig->SetBool(*ConfigIniSection, TEXT("DisplayActorsCount"), GetDisplayActorsCountState(), GEditorUserSettingsIni);
|
|
}
|
|
|
|
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
|