Files
UnrealEngineUWP/Engine/Source/Developer/ModuleUI/Private/SModuleUI.cpp

320 lines
9.0 KiB
C++

// Copyright 1998-2014 Epic Games, Inc. All Rights Reserved.
#include "ModuleUIPrivatePCH.h"
#include "HotReloadInterface.h"
BEGIN_SLATE_FUNCTION_BUILD_OPTIMIZATION
void SModuleUI::Construct(const SModuleUI::FArguments& InArgs)
{
#define LOCTEXT_NAMESPACE "ModuleUI"
ChildSlot
.Padding( FMargin(8) )
[
SNew( SVerticalBox )
// List of modules
+ SVerticalBox::Slot()
.FillHeight( 1.0f ) // We want the list to stretch vertically to fill up the user-resizable space
[
SAssignNew( ModuleListView, SModuleListView )
.ItemHeight( 24 )
.ListItemsSource( &ModuleListItems )
.OnGenerateRow( this, &SModuleUI::OnGenerateWidgetForModuleListView )
.HeaderRow
(
SNew(SHeaderRow)
+SHeaderRow::Column("ModuleName")
.DefaultLabel(NSLOCTEXT("ModuleUI", "ModuleName", "Module").ToString())
.FillWidth(200)
+SHeaderRow::Column("ModuleActions")
.DefaultLabel(NSLOCTEXT("ModuleUI", "ModuleActions", "Actions").ToString())
.FillWidth(1000)
)
]
];
#undef LOCTEXT_NAMESPACE
// Register to find out about module changes
FModuleManager::Get().OnModulesChanged().AddSP( this, &SModuleUI::OnModulesChanged );
// Gather data from module manager
UpdateModuleListItems();
}
END_SLATE_FUNCTION_BUILD_OPTIMIZATION
SModuleUI::~SModuleUI()
{
// Unregister callbacks
FModuleManager::Get().OnModulesChanged().RemoveAll( this );
}
TSharedRef<ITableRow> SModuleUI::OnGenerateWidgetForModuleListView(TSharedPtr< FModuleListItem > InItem, const TSharedRef<STableViewBase>& OwnerTable)
{
#define LOCTEXT_NAMESPACE "ModuleUI"
class SModuleItemWidget : public SMultiColumnTableRow< TSharedPtr< FModuleListItem > >
{
public:
SLATE_BEGIN_ARGS( SModuleItemWidget ){}
SLATE_END_ARGS()
void Construct( const FArguments& InArgs, const TSharedRef<STableViewBase>& InOwnerTable, TSharedPtr<FModuleListItem> InListItem )
{
Item = InListItem;
SMultiColumnTableRow< TSharedPtr< FModuleListItem > >::Construct( FSuperRowType::FArguments(), InOwnerTable );
}
TSharedRef<SWidget> GenerateWidgetForColumn( const FName& ColumnName )
{
if ( ColumnName == "ModuleName" )
{
return
SNew( STextBlock )
.Text( Item->ModuleName.ToString() );
}
else if ( ColumnName == "ModuleActions" )
{
return
SNew( SHorizontalBox )
// Load button
+ SHorizontalBox::Slot()
.AutoWidth()
.Padding( 2.0f, 0.0f )
[
SNew( SButton )
.Visibility( Item.ToSharedRef(), &FModuleListItem::GetVisibilityBasedOnUnloadedState )
.Text( LOCTEXT("Load", "Load") )
.OnClicked( Item.ToSharedRef(), &FModuleListItem::OnLoadClicked )
]
// Unload button
+ SHorizontalBox::Slot()
.AutoWidth()
.Padding( 2.0f, 0.0f )
[
SNew( SButton )
.Visibility( Item.ToSharedRef(), &FModuleListItem::GetVisibilityBasedOnLoadedAndShutdownableState )
.Text( LOCTEXT("Unload", "Unload") )
.OnClicked( Item.ToSharedRef(), &FModuleListItem::OnUnloadClicked )
]
// Reload button
+ SHorizontalBox::Slot()
.AutoWidth()
.Padding( 2.0f, 0.0f )
[
SNew( SButton )
.Visibility( Item.ToSharedRef(), &FModuleListItem::GetVisibilityBasedOnReloadableState )
.Text( LOCTEXT("Reload", "Reload") )
.OnClicked( Item.ToSharedRef(), &FModuleListItem::OnReloadClicked )
]
// Recompile button
+ SHorizontalBox::Slot()
.AutoWidth()
.Padding( 2.0f, 0.0f )
[
SNew( SButton )
.Visibility( Item.ToSharedRef(), &FModuleListItem::GetVisibilityBasedOnRecompilableState )
.Text( LOCTEXT("Recompile", "Recompile") )
.OnClicked( Item.ToSharedRef(), &FModuleListItem::OnRecompileClicked )
];
}
else
{
return SNew(STextBlock) .Text(LOCTEXT("UnknownColumn", "Unknown Column"));
}
}
TSharedPtr< FModuleListItem > Item;
};
return SNew( SModuleItemWidget, OwnerTable, InItem );
#undef LOCTEXT_NAMESPACE
}
void SModuleUI::OnModulesChanged( FName ModuleThatChanged, EModuleChangeReason ReasonForChange )
{
// @todo: Consider using dirty bit for this instead, refresh on demand
UpdateModuleListItems();
}
void SModuleUI::UpdateModuleListItems()
{
ModuleListItems.Reset();
TArray< FModuleStatus > ModuleStatuses;
FModuleManager::Get().QueryModules( ModuleStatuses );
for( TArray< FModuleStatus >::TConstIterator ModuleIt( ModuleStatuses ); ModuleIt; ++ModuleIt )
{
const FModuleStatus& ModuleStatus = *ModuleIt;
FName ModuleName(*ModuleStatus.Name);
TSharedRef< FModuleListItem > NewItem( new FModuleListItem() );
NewItem->ModuleName = ModuleName;
ModuleListItems.Add( NewItem );
}
// Sort the list of modules alphabetically
struct FModuleSorter
{
FORCEINLINE bool operator()( const TSharedPtr<FModuleListItem>& A, const TSharedPtr<FModuleListItem>& B ) const
{
return A->ModuleName < B->ModuleName;
}
};
ModuleListItems.Sort( FModuleSorter() );
// Update the list view if we have one
if( ModuleListView.IsValid() )
{
ModuleListView->RequestListRefresh();
}
}
FReply SModuleUI::FModuleListItem::OnLoadClicked()
{
GEngine->DeferredCommands.Add( FString::Printf( TEXT( "Module Load %s" ), *ModuleName.ToString() ) );
return FReply::Handled();
}
FReply SModuleUI::FModuleListItem::OnUnloadClicked()
{
GEngine->DeferredCommands.Add( FString::Printf( TEXT( "Module Unload %s" ), *ModuleName.ToString() ) );
return FReply::Handled();
}
FReply SModuleUI::FModuleListItem::OnReloadClicked()
{
GEngine->DeferredCommands.Add( FString::Printf( TEXT( "Module Reload %s" ), *ModuleName.ToString() ) );
return FReply::Handled();
}
FReply SModuleUI::FModuleListItem::OnRecompileClicked()
{
const bool bShowProgressDialog = true;
const bool bShowCancelButton = false;
FFormatNamedArguments Args;
Args.Add( TEXT("ModuleName"), FText::FromName( ModuleName ) );
GWarn->BeginSlowTask( FText::Format( NSLOCTEXT("ModuleUI", "Recompile_SlowTaskName", "Compiling {ModuleName}..."), Args ), bShowProgressDialog, bShowCancelButton );
// Does the module have any UObject classes in it? If so we'll use HotReload to recompile it.
FModuleStatus ModuleStatus;
if( ensure( FModuleManager::Get().QueryModule( ModuleName, ModuleStatus ) ) )
{
//@todo This is for content-only packages that show up in the
// Module UI... don't crash when recompile is clicked
if (FPaths::IsProjectFilePathSet())
{
if (ModuleStatus.bIsLoaded == false)
{
if (FPlatformFileManager::Get().GetPlatformFile().FileExists(*ModuleStatus.FilePath) == false)
{
UE_LOG(LogTemp, Display, TEXT("Unable to recompile module %s... Is it a content-only module?"), *ModuleName.ToString());
GWarn->EndSlowTask();
return FReply::Handled();
}
}
}
TArray< UPackage* > PackagesToRebind;
if( ModuleStatus.bIsLoaded )
{
const bool bIsHotReloadable = FModuleManager::Get().DoesLoadedModuleHaveUObjects( ModuleName );
if( bIsHotReloadable )
{
// Is there a UPackage with the same name as this module?
FString PotentialPackageName = FString(TEXT("/Script/")) + ModuleName.ToString();
UPackage* Package = FindPackage( NULL, *PotentialPackageName);
if( Package != NULL )
{
PackagesToRebind.Add( Package );
}
}
}
IHotReloadInterface& HotReloadSupport = FModuleManager::LoadModuleChecked<IHotReloadInterface>("HotReload");
if( PackagesToRebind.Num() > 0 )
{
// Perform a hot reload
const bool bWaitForCompletion = true;
HotReloadSupport.RebindPackages(PackagesToRebind, TArray<FName>(), bWaitForCompletion, *GLog);
}
else
{
// Perform a regular unload, then reload
const bool bReloadAfterRecompile = true;
HotReloadSupport.RecompileModule( ModuleName, bReloadAfterRecompile, *GLog );
}
}
GWarn->EndSlowTask();
return FReply::Handled();
}
EVisibility SModuleUI::FModuleListItem::GetVisibilityBasedOnLoadedAndShutdownableState() const
{
if ( GIsSavingPackage || GIsGarbageCollecting )
{
return EVisibility::Hidden;
}
const bool bIsHotReloadable = FModuleManager::Get().DoesLoadedModuleHaveUObjects(ModuleName);
const bool bCanShutDown = ( FModuleManager::Get().IsModuleLoaded(ModuleName)
&& !bIsHotReloadable
&& FModuleManager::Get().GetModule(ModuleName)->SupportsDynamicReloading() );
return bCanShutDown ? EVisibility::Visible : EVisibility::Hidden;
}
EVisibility SModuleUI::FModuleListItem::GetVisibilityBasedOnReloadableState() const
{
return GetVisibilityBasedOnLoadedAndShutdownableState();
};
EVisibility SModuleUI::FModuleListItem::GetVisibilityBasedOnRecompilableState() const
{
if ( GIsSavingPackage || GIsGarbageCollecting )
{
return EVisibility::Hidden;
}
const bool bIsHotReloadable = FModuleManager::Get().DoesLoadedModuleHaveUObjects(ModuleName);
const bool bCanReload = ( !FModuleManager::Get().IsModuleLoaded(ModuleName)
|| FModuleManager::Get().GetModule(ModuleName)->SupportsDynamicReloading()
|| bIsHotReloadable );
return bCanReload ? EVisibility::Visible : EVisibility::Hidden;
}
EVisibility SModuleUI::FModuleListItem::GetVisibilityBasedOnUnloadedState() const
{
return FModuleManager::Get().IsModuleLoaded( ModuleName ) ? EVisibility::Hidden : EVisibility::Visible;
}