Files
UnrealEngineUWP/Engine/Source/Editor/Levels/Private/LevelViewModel.cpp
Max Preussner f167dce37e Slate: Moved TestSuite and ColorPicker into new module AppFramework
The AppFramework module is intended to be used for compound widgets and UI related classes that are too specific (not basic enough) for Slate, but also not Editor specific (reusable in non-Editor applications and games). The test suite has been moved in its entirety for now, but core widget specific test classes will eventually be split off and moved back into Slate, so that they can live alongside of their corresponding widgets.

Other changes:
- moved to "include what you use" scheme for SColorPicker
- broke out color picker related widgets that may be reusable
- added forward declarations to reduce header include dependencies

#CodeReview: saul.abreu

[CL 2275496 by Max Preussner in Main branch]
2014-08-27 20:35:19 -04:00

652 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"
#include "SColorPicker.h"
#define LOCTEXT_NAMESPACE "Level"
FLevelViewModel::FLevelViewModel( const TWeakObjectPtr< class ULevel >& InLevel,
const TWeakObjectPtr< class ULevelStreaming >& InLevelStreaming,
const TWeakObjectPtr< UEditorEngine >& InEditor )
: Editor( InEditor )
, Level( InLevel )
, LevelStreaming( InLevelStreaming )
, 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->GetWorldAssetPackageName();
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->LevelColor;
}
}
return FLinearColor::White;
}
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 );
FLinearColor NewColor = StreamingLevel->LevelColor;
TArray<FLinearColor*> ColorArray;
ColorArray.Add(&NewColor);
FColorPickerArgs PickerArgs;
PickerArgs.bIsModal = true;
PickerArgs.DisplayGamma = TAttribute<float>::Create( TAttribute<float>::FGetter::CreateUObject(GEngine, &UEngine::GetDisplayGamma) );
PickerArgs.LinearColorArray = &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->LevelColor = 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