Files
UnrealEngineUWP/Engine/Source/Editor/WorldBrowser/Private/LevelCollectionModel.cpp
Thomas Sarkanen be75fe1eca Updated revision display to display strings rather than revision indices
API break: added new pure virtual ISourceControlProvider::UsesChangelists()
API break: added new pure virtual ISourceControlState::FindHistoryRevision(const FString&)
API break: added new pure virtual ISourceControlRevision::GetRevision()

Implementing a Git provider requires us to be able to display revisions that are not indices as Git revisions are hashes. This updates the relvant code to allow us to display these revisions correctly.

[CL 2411986 by Thomas Sarkanen in Main branch]
2015-01-20 05:48:14 -05:00

1813 lines
49 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.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)
{
FSourceControlWindows::PromptForCheckin(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::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()
{
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();
}
void FLevelCollectionModel::OnActorSelectionChanged(UObject* obj)
{
OnActorOrLevelSelectionChanged();
}
void FLevelCollectionModel::OnActorOrLevelSelectionChanged()
{
bSelectionHasChanged = true;
}
#undef LOCTEXT_NAMESPACE