Files
UnrealEngineUWP/Engine/Source/Editor/Levels/Private/LevelViewModel.cpp
Andrew Brown fbf585cb1b Toggling Level visibility no longer forces layer visibility
#ttp 340965 - UE4-Fortnite: Editor: levels: every time you toggle visibility on a level it makes all Layers visible, yikes

#branch UE4

#change additionally, making a level current no longer forces the layer visibility either.

reviewed by Thomas.Sarkanen

[CL 2217507 by Andrew Brown in Main branch]
2014-07-15 04:48:45 -04:00

651 lines
14 KiB
C++

// Copyright 1998-2014 Epic Games, Inc. All Rights Reserved.
#include "LevelsPrivatePCH.h"
#include "Engine/LevelScriptBlueprint.h"
#include "LevelViewModel.h"
#include "LevelUtils.h"
#include "EditorLevelUtils.h"
#include "Toolkits/AssetEditorManager.h"
#include "EditorSupportDelegates.h"
#define LOCTEXT_NAMESPACE "Level"
FLevelViewModel::FLevelViewModel( const TWeakObjectPtr< class ULevel >& InLevel,
const TWeakObjectPtr< class ULevelStreaming >& InLevelStreaming,
const TWeakObjectPtr< UEditorEngine >& InEditor )
: Level( InLevel )
, LevelStreaming( InLevelStreaming )
, Editor( InEditor )
, LevelActorsCount(0)
{
}
void FLevelViewModel::Initialize()
{
Editor->RegisterForUndo( this );
}
FLevelViewModel::~FLevelViewModel()
{
Editor->UnregisterForUndo( this );
}
void FLevelViewModel::RefreshStreamingLevelIndex()
{
if ( IsLevel() )
{
UWorld *OwningWorld = Level->OwningWorld;
check( OwningWorld );
for( int32 LevelIndex = 0 ; LevelIndex < OwningWorld->StreamingLevels.Num() ; ++LevelIndex )
{
ULevelStreaming *StreamingLevel = OwningWorld->StreamingLevels[LevelIndex];
if ( Level.Get() == StreamingLevel->GetLoadedLevel() )
{
StreamingLevelIndex = LevelIndex;
LevelStreaming = StreamingLevel;
break;
}
}
}
}
FName FLevelViewModel::GetFName() const
{
if ( IsLevel() )
{
return Level->GetOutermost()->GetFName();
}
return NAME_None;
}
FString FLevelViewModel::GetName(bool bForceDisplayPath /*=false*/, bool bDisplayTags /*=true*/) const
{
FString DisplayName;
if( IsLevel() )
{
if ( bDisplayTags && IsPersistent() )
{
DisplayName += LOCTEXT("PersistentTag", "Persistent Level").ToString();
}
else
{
DisplayName += Level->GetOutermost()->GetName();
bool bDisplayPathsInLevelBrowser = (GetDefault<ULevelBrowserSettings>()->bDisplayPaths);
if ( !(bDisplayPathsInLevelBrowser || bForceDisplayPath) )
{
DisplayName = FPaths::GetCleanFilename(DisplayName);
}
}
if ( bDisplayTags && IsDirty() )
{
DisplayName += TEXT(" * ");
}
if ( bDisplayTags && (IsCurrent()) )
{
DisplayName += LOCTEXT("CurrentLevelTag", " [Current Level]").ToString();
}
}
else if ( IsLevelStreaming() )
{
DisplayName += LevelStreaming->PackageName.ToString();
bool bDisplayPathsInLevelBrowser = (GetDefault<ULevelBrowserSettings>()->bDisplayPaths);
if ( !(bDisplayPathsInLevelBrowser || bForceDisplayPath) )
{
DisplayName = FPaths::GetCleanFilename(DisplayName);
}
if ( bDisplayTags && IsDirty() )
{
DisplayName += TEXT(" * ");
}
DisplayName += LOCTEXT("MissingLevelErrorText", " [Missing Level]").ToString();
}
return DisplayName;
}
FString FLevelViewModel::GetDisplayName() const
{
return GetName();
}
FString FLevelViewModel::GetActorCountString() const
{
return FString::Printf(TEXT( "%i" ), LevelActorsCount);
}
FString FLevelViewModel::GetLightmassSizeString() const
{
FString MemorySizeString;
ULevel* CurLevel = Level.Get();
if ( CurLevel && GetDefault<ULevelBrowserSettings>()->bDisplayLightmassSize )
{
// Update metrics
static const float ByteConversion = 1.0f / 1024.0f;
float LightmapSize = CurLevel->LightmapTotalSize * ByteConversion;
MemorySizeString += FString::Printf( TEXT( "%.2f" ), LightmapSize );
}
return MemorySizeString;
}
FString FLevelViewModel::GetFileSizeString() const
{
FString MemorySizeString;
ULevel* CurLevel = Level.Get();
if ( CurLevel && GetDefault<ULevelBrowserSettings>()->bDisplayFileSize )
{
// Update metrics
static const float ByteConversion = 1.0f / 1024.0f;
float FileSize = CurLevel->GetOutermost()->GetFileSize() * ByteConversion * ByteConversion;
MemorySizeString += FString::Printf( TEXT( "%.2f" ), FileSize );
}
return MemorySizeString;
}
void FLevelViewModel::ClearDirtyFlag()
{
if ( IsLevel() )
{
return Level->GetOutermost()->SetDirtyFlag(false);
}
else if ( IsLevelStreaming() )
{
return LevelStreaming->GetOutermost()->SetDirtyFlag(false);
}
}
bool FLevelViewModel::IsDirty() const
{
if ( IsLevel() )
{
return Level->GetOutermost()->IsDirty();
}
else if ( IsLevelStreaming() )
{
return LevelStreaming->GetOutermost()->IsDirty();
}
else
{
return false;
}
}
bool FLevelViewModel::IsCurrent() const
{
if ( IsLevel() )
{
return Level->IsCurrentLevel();
}
else
{
return false;
}
}
bool FLevelViewModel::IsPersistent() const
{
if( !Level.IsValid() )
{
return false;
}
return ( Level->IsPersistentLevel() );
}
bool FLevelViewModel::IsLevel() const
{
return Level.IsValid();
}
bool FLevelViewModel::IsLevelStreaming() const
{
return LevelStreaming.IsValid();
}
bool FLevelViewModel::IsVisible() const
{
if( !Level.IsValid() )
{
return false;
}
return ( FLevelUtils::IsLevelVisible(Level.Get()) );
}
void FLevelViewModel::ToggleVisibility()
{
if( !Level.IsValid() )
{
return;
}
SetVisible( !IsVisible() );
}
void FLevelViewModel::SetVisible(bool bVisible)
{
//don't create unnecessary transactions
if ( IsVisible() == bVisible )
{
return;
}
const bool oldIsDirty = IsDirty();
const FScopedTransaction Transaction( LOCTEXT("ToggleVisibility", "Toggle Level Visibility") );
//this call hides all owned actors, etc
EditorLevelUtils::SetLevelVisibility( Level.Get(), bVisible, false );
if( !oldIsDirty )
{
// don't set the dirty flag if we're just changing the visibility of the level within the editor
ClearDirtyFlag();
}
}
bool FLevelViewModel::IsReadOnly() const
{
const UPackage* pPackage = Cast<UPackage>( Level->GetOutermost() );
if ( pPackage )
{
FString PackageFileName;
if ( FPackageName::DoesPackageExist( pPackage->GetName(), NULL, &PackageFileName ) )
{
return IFileManager::Get().IsReadOnly( *PackageFileName );
}
}
return false;
}
bool FLevelViewModel::IsLocked() const
{
if( !Level.IsValid() )
{
return false;
}
// Don't permit spawning in read only levels if they are locked
if ( GIsEditor && !GIsEditorLoadingPackage )
{
if ( GEngine && GEngine->bLockReadOnlyLevels )
{
if(IsReadOnly())
{
return true;
}
}
}
return ( FLevelUtils::IsLevelLocked(Level.Get()) );
}
bool FLevelViewModel::IsValid() const
{
bool bValid = Level.IsValid() || LevelStreaming.IsValid();
return bValid;
}
void FLevelViewModel::ToggleLock()
{
if( !Level.IsValid() )
{
return;
}
SetLocked( !IsLocked() );
}
/**
* Attempt to lock/unlock the level of this window
*
* @param bLocked If true, attempt to lock the level; If false, attempt to unlock the level
*/
void FLevelViewModel::SetLocked(bool bLocked)
{
if( !Level.IsValid() )
{
return;
}
// Do nothing if attempting to set the level to the same locked state or if trying to lock/unlock the p-level
if ( bLocked == IsLocked() || IsPersistent() )
{
return;
}
// If locking the level, deselect all of its actors and BSP surfaces
if ( bLocked )
{
USelection* SelectedActors = GEditor->GetSelectedActors();
SelectedActors->Modify();
// Deselect all level actors
for ( TArray<AActor*>::TConstIterator LevelActorIterator( Level->Actors ); LevelActorIterator; ++LevelActorIterator )
{
AActor* CurActor = *LevelActorIterator;
if ( CurActor )
{
SelectedActors->Deselect( CurActor );
}
}
// Deselect all level BSP surfaces
EditorLevelUtils::DeselectAllSurfacesInLevel(Level.Get());
// Tell the editor selection status was changed.
GEditor->NoteSelectionChange();
// If locking the current level, reset the p-level as the current level
//@todo: fix this!
}
// Change the level's locked status
FLevelUtils::ToggleLevelLock( Level.Get() );
}
void FLevelViewModel::SetStreamingClass( UClass *LevelStreamingClass )
{
if ( IsPersistent() || !IsLevel() )
{
// Invalid operations for the persistent level
return;
}
ULevelStreaming* StreamingLevel = FLevelUtils::FindStreamingLevel( Level.Get() );
if ( StreamingLevel )
{
EditorLevelUtils::SetStreamingClassForLevel( StreamingLevel, LevelStreamingClass );
}
}
void FLevelViewModel::MakeLevelCurrent()
{
// If something is selected and not already current . . .
if ( Level.IsValid() && !Level.Get()->IsCurrentLevel() )
{
EditorLevelUtils::MakeLevelCurrent(Level.Get());
}
Refresh();
}
void FLevelViewModel::Save()
{
if ( !IsLevel() )
{
return;
}
if ( !IsVisible() )
{
FMessageDialog::Open( EAppMsgType::Ok, NSLOCTEXT("UnrealEd", "UnableToSaveInvisibleLevels", "Save aborted. Levels must be made visible before they can be saved.") );
return;
}
else if ( IsLocked() )
{
FMessageDialog::Open( EAppMsgType::Ok, NSLOCTEXT("UnrealEd", "UnableToSaveLockedLevels", "Save aborted. Level must be unlocked before it can be saved.") );
return;
}
// Prompt the user to check out the level from source control before saving if it's currently under source control
if ( FEditorFileUtils::PromptToCheckoutLevels( false, Level.Get() ) )
{
FEditorFileUtils::SaveLevel( Level.Get() );
}
}
bool FLevelViewModel::HasKismet() const
{
if( !Level.IsValid() )
{
return false;
}
return true;
}
void FLevelViewModel::OpenKismet()
{
if( !Level.IsValid() )
{
return;
}
ULevelScriptBlueprint* LevelScriptBlueprint = Level.Get()->GetLevelScriptBlueprint();
if( LevelScriptBlueprint )
{
FAssetEditorManager::Get().OpenEditorForAsset(LevelScriptBlueprint);
}
else
{
FMessageDialog::Open( EAppMsgType::Ok, NSLOCTEXT("UnrealEd", "UnableToCreateLevelScript", "Unable to find or create a level blueprint for this level.") );
}
}
FSlateColor FLevelViewModel::GetColor() const
{
if( Level.IsValid() && !Level->IsPersistentLevel() )
{
ULevelStreaming* StreamingLevel = FLevelUtils::FindStreamingLevel( Level.Get() );
if ( StreamingLevel )
{
return StreamingLevel->DrawColor.ReinterpretAsLinear();
}
}
return FLinearColor( 1.0f, 1.0f, 1.0f, 1.0f );
}
void FLevelViewModel::OnColorPickerCancelled(FLinearColor Color)
{
bColorPickerOK = false;
}
void FLevelViewModel::ChangeColor(const TSharedRef<SWidget>& InPickerParentWidget)
{
if( !Level.IsValid() )
{
return;
}
if ( !Level->IsPersistentLevel())
{
// Initialize the color data for the picker window.
ULevelStreaming* StreamingLevel = FLevelUtils::FindStreamingLevel( Level.Get() );
check( StreamingLevel );
FColor NewColor = StreamingLevel->DrawColor;
TArray<FColor*> ColorArray;
ColorArray.Add(&NewColor);
FColorPickerArgs PickerArgs;
PickerArgs.bIsModal = true;
PickerArgs.DisplayGamma = TAttribute<float>::Create( TAttribute<float>::FGetter::CreateUObject(GEngine, &UEngine::GetDisplayGamma) );
PickerArgs.ColorArray = &ColorArray;
PickerArgs.OnColorPickerCancelled = FOnColorPickerCancelled::CreateSP(this, &FLevelViewModel::OnColorPickerCancelled);
PickerArgs.ParentWidget = InPickerParentWidget;
// ensure this is true, will be set to false in OnColorPickerCancelled if necessary
bColorPickerOK = true;
if (OpenColorPicker(PickerArgs))
{
if ( bColorPickerOK )
{
StreamingLevel->DrawColor = NewColor;
StreamingLevel->Modify();
// Update the loaded level's components so the change in color will apply immediately
ULevel* LoadedLevel = StreamingLevel->GetLoadedLevel();
if ( LoadedLevel )
{
LoadedLevel->UpdateLevelComponents(false);
}
ULevel::LevelDirtiedEvent.Broadcast();
}
FEditorSupportDelegates::RedrawAllViewports.Broadcast();
}
}
}
//@todo: add actor drag+drop support
bool FLevelViewModel::CanAssignActors( const TArray< TWeakObjectPtr<AActor> > Actors, FText& OutMessage ) const
{
return false;
}
bool FLevelViewModel::CanAssignActor(const TWeakObjectPtr<AActor> Actor, FText& OutMessage) const
{
return true;
}
void FLevelViewModel::AppendActors( TArray< TWeakObjectPtr< AActor > >& InActors ) const
{
}
void FLevelViewModel::AppendActorsOfSpecificType( TArray< TWeakObjectPtr< AActor > >& InActors, const TWeakObjectPtr< UClass >& Class )
{
}
void FLevelViewModel::AddActor( const TWeakObjectPtr< AActor >& Actor )
{
}
void FLevelViewModel::AddActors( const TArray< TWeakObjectPtr< AActor > >& Actors )
{
}
void FLevelViewModel::RemoveActors( const TArray< TWeakObjectPtr< AActor > >& Actors )
{
}
void FLevelViewModel::RemoveActor( const TWeakObjectPtr< AActor >& Actor )
{
}
void FLevelViewModel::SelectActors( bool bSelect, bool bNotify, bool bSelectEvenIfHidden, const TSharedPtr< IFilter< const TWeakObjectPtr< AActor >& > >& Filter )
{
if( !Level.IsValid() || IsLocked() )
{
return;
}
Editor->GetSelectedActors()->BeginBatchSelectOperation();
bool bChangesOccurred = false;
// Iterate over all actors, looking for actors in this level.
ULevel* RawLevel = Level.Get();
for ( int32 ActorIndex = 2 ; ActorIndex < RawLevel->Actors.Num() ; ++ActorIndex )
{
AActor* Actor = RawLevel->Actors[ ActorIndex ];
if ( Actor )
{
if( Filter.IsValid() && !Filter->PassesFilter( Actor ) )
{
continue;
}
bool bNotifyForActor = false;
Editor->GetSelectedActors()->Modify();
Editor->SelectActor( Actor, bSelect, bNotifyForActor, bSelectEvenIfHidden );
bChangesOccurred = true;
}
}
Editor->GetSelectedActors()->EndBatchSelectOperation();
if( bNotify )
{
Editor->NoteSelectionChange();
}
}
void FLevelViewModel::SelectActorsOfSpecificType( const TWeakObjectPtr< UClass >& Class )
{
}
void FLevelViewModel::SetDataSource( const TWeakObjectPtr< ULevel >& InLevel )
{
if( Level == InLevel )
{
return;
}
Level = InLevel;
Refresh();
}
const TWeakObjectPtr< ULevel > FLevelViewModel::GetLevel()
{
return Level;
}
const TWeakObjectPtr< ULevelStreaming > FLevelViewModel::GetLevelStreaming()
{
return LevelStreaming;
}
void FLevelViewModel::OnLevelsChanged( const ELevelsAction::Type Action, const ULevel* ChangedLevel, const FName& ChangedProperty )
{
ChangedEvent.Broadcast();
}
void FLevelViewModel::Refresh()
{
OnLevelsChanged( ELevelsAction::Reset, NULL, NAME_None );
}
void FLevelViewModel::UpdateLevelActorsCount()
{
LevelActorsCount = 0;
ULevel* CurLevel = Level.Get();
if (CurLevel)
{
// Count the actors contained in these levels
// NOTE: We subtract two here to omit "default actors" in the count (default brush, and WorldSettings)
LevelActorsCount = CurLevel->Actors.Num()-2;
// Count deleted actors
int32 NumDeletedActors = 0;
for (int32 ActorIdx = 0; ActorIdx < CurLevel->Actors.Num(); ++ActorIdx)
{
if (!CurLevel->Actors[ActorIdx])
{
++NumDeletedActors;
}
}
// Subtract deleted actors from the actor count
LevelActorsCount -= NumDeletedActors;
}
}
#undef LOCTEXT_NAMESPACE