Files
UnrealEngineUWP/Engine/Source/Editor/MainFrame/Private/Frame/MainFrameHandler.h

296 lines
9.1 KiB
C
Raw Normal View History

// Copyright 1998-2017 Epic Games, Inc. All Rights Reserved.
#pragma once
Copying //UE4/Dev-Build to //UE4/Dev-Main (Source: //UE4/Dev-Build @ 3209340) #lockdown Nick.Penwarden #rb none ========================== MAJOR FEATURES + CHANGES ========================== Change 3209340 on 2016/11/23 by Ben.Marsh Convert UE4 codebase to an "include what you use" model - where every header just includes the dependencies it needs, rather than every source file including large monolithic headers like Engine.h and UnrealEd.h. Measured full rebuild times around 2x faster using XGE on Windows, and improvements of 25% or more for incremental builds and full rebuilds on most other platforms. * Every header now includes everything it needs to compile. * There's a CoreMinimal.h header that gets you a set of ubiquitous types from Core (eg. FString, FName, TArray, FVector, etc...). Most headers now include this first. * There's a CoreTypes.h header that sets up primitive UE4 types and build macros (int32, PLATFORM_WIN64, etc...). All headers in Core include this first, as does CoreMinimal.h. * Every .cpp file includes its matching .h file first. * This helps validate that each header is including everything it needs to compile. * No engine code includes a monolithic header such as Engine.h or UnrealEd.h any more. * You will get a warning if you try to include one of these from the engine. They still exist for compatibility with game projects and do not produce warnings when included there. * There have only been minor changes to our internal games down to accommodate these changes. The intent is for this to be as seamless as possible. * No engine code explicitly includes a precompiled header any more. * We still use PCHs, but they're force-included on the compiler command line by UnrealBuildTool instead. This lets us tune what they contain without breaking any existing include dependencies. * PCHs are generated by a tool to get a statistical amount of coverage for the source files using it, and I've seeded the new shared PCHs to contain any header included by > 15% of source files. Tool used to generate this transform is at Engine\Source\Programs\IncludeTool. [CL 3209342 by Ben Marsh in Main branch]
2016-11-23 15:48:37 -05:00
#include "CoreMinimal.h"
#include "Modules/ModuleManager.h"
#include "Widgets/SWindow.h"
#include "UnrealEdMisc.h"
#include "Misc/App.h"
#include "Framework/Application/SlateApplication.h"
#include "Framework/Docking/TabManager.h"
#include "Framework/Docking/LayoutService.h"
#include "EngineGlobals.h"
#include "Toolkits/AssetEditorManager.h"
#include "Editor/UnrealEdEngine.h"
#include "EditorModeManager.h"
#include "EditorModes.h"
#include "FileHelpers.h"
#include "UnrealEdGlobals.h"
#include "LevelEditor.h"
#include "ILevelViewport.h"
#include "MainFrameLog.h"
const FText StaticGetApplicationTitle( const bool bIncludeGameName );
/**
* Helper class that handles talking to the Slate App Manager.
*/
class FMainFrameHandler : public TSharedFromThis<FMainFrameHandler>
{
public:
/**
* Shuts down the Editor.
*/
void ShutDownEditor( TSharedRef<SDockTab> TabBeingClosed )
{
ShutDownEditor();
}
/**
* Shuts down the Editor.
*/
void ShutDownEditor( );
/**
* Checks whether the main frame tab can be closed.
*
* @return true if the tab can be closed, false otherwise.
*/
bool CanCloseTab()
{
if ( GIsRequestingExit )
{
UE_LOG(LogMainFrame, Warning, TEXT("MainFrame: Shutdown already in progress when CanCloseTab was queried, approve tab for closure."));
return true;
}
return CanCloseEditor();
}
/**
* Checks whether the Editor tab can be closed.
*
* @return true if the Editor can be closed, false otherwise.
*/
bool CanCloseEditor()
{
if ( FSlateApplication::IsInitialized() && !FSlateApplication::Get().IsNormalExecution() )
{
// DEBUGGER EXIT PATH
// The debugger is running we cannot actually close now.
// We will stop the debugger and enque a request to close the editor on the next frame.
// Stop debugging.
FSlateApplication::Get().LeaveDebuggingMode();
// Defer the call RequestCloseEditor() till next tick.
GEngine->DeferredCommands.Add( TEXT("CLOSE_SLATE_MAINFRAME") );
// Cannot exit right now.
return false;
}
Merging UE4-Streaming to UE4 - Linkers are no longer UObjects. Renamed ULinker, ULinkerLoad and ULinkerSave to FLinker, FLinkerLoad, FLinkerSave respectively - Linkers are now associated with their UPackages - Linker version is now stored in UPackages - Async loading is now performed on a separate thread (if platform supports it and only in cooked builds), with the exception of PostLoad which is still done on the game thread - Added UObject::IsPostLoadThreadSafe() function to determine if PostLoad is thread safe and can be executed on the async loading thread (defaults to false) - UObject creation is now thread safe and can be performed on any thread - Move many of the linker/UObject globals into FUObjectThreadContext (TLS) - GetAsyncLoadPercentage() now takes PostLoad into account - More async loading stats - Added AtomicallySetFlags/ClearFlags to UObject - Made FModuleManager thread safe. - Added FGCScopeGuard as means of preventing GC from executing from non-game thread - It's possible to disable async loading thread through ini settings. - Cancelling async loading will now also trigger GC - Implemented a basic version of async streaming priorities. Change 2410813 by Mikolaj Sieluzycki: Change Sleep in while loop to ConditionalSleep in FMultiReaderSingleWriterGT Change 2410734 by Mikolaj Sieluzycki: Make FModuleManager thread safe. Change 2399879 by Mikolaj Sieluzycki: Basic version of async streaming priorities. Change 2410707 by Mikolaj Sieluzycki: Implement conditional and no stat versions of sleep. Change 2371939 by Robert Manuszewski: Async Loading Improvements: adding more stats (accumulators) Change 2372403 by Robert Manuszewski: Fixing compile errors when STATs are not enabled Change 2371526 by Robert Manuszewski: AsyncLoading Improvements (WIP) Change 2407198 by Robert Manuszewski: Re-implementing delegate fixes for Async Loading Change 2407425 by Robert Manuszewski: Re-implementing cancelling async loading in the async loading branch. Change 2484362 by Robert Manuszewski: Making it possible to disable async loading thread through ini settings. Change 2484744 by Robert Manuszewski: Minimizing locks in GC and other threads when handling UObjects Change 2480190 by Robert Manuszewski: Fixing infinite stall after canceling async loading in non-cooked builds Change 2484268 by Robert Manuszewski: Fixing crash when allocating permanent object pool. Change 2489761 by Robert Manuszewski: Fixing BulkData using linker archive on the main thread even if the linker was created on the async loading thread. Change 2493624 by Robert Manuszewski: Cancelling async loading will now also trigger GC Change 2487881 by Robert Manuszewski: Making ShaderIdMap operations thread safe. Change 2488067 by Robert Manuszewski: Fixing GetAsyncLoadPercentage. It will now also respect PostLoad. Change 2458640 by Robert Manuszewski: Fixing crash in PIE Change 2458825 by Robert Manuszewski: Fixing a few crashes when streaming and the package is missing. Change 2476935 by Robert Manuszewski: Fixing crash while async loading ANavigationData Change 2477361 by Robert Manuszewski: Fixing crashes in cooked game Change 2480095 by Robert Manuszewski: Making FUObjectArray more thread safe Change 2475443 by Robert Manuszewski: Re-enabling single-threaded async loading path for the editor and platforms that don't support multithreading. Change 2475458 by Robert Manuszewski: Making sure bulk data is only loaded on a separate thread if it's not being loaded on the async loading thread. Change 2476661 by Robert Manuszewski: Fixing FlushAsyncLoading not flushing everything Change 2401089 by Jaroslaw Surowiec: Core - Added AtomicallySetFlags/ClearFlags to UObject, added a comment to ThisThreadAtomicallyClearedRFUnreachable [CL 2498249 by Robert Manuszewski in Main branch]
2015-04-01 03:03:18 -04:00
else if (GIsSavingPackage || IsGarbageCollecting())
{
// SAVING/GC PATH
// We're currently saving or garbage collecting and can't close the editor just yet.
// We will have to wait and try to request to close the editor on the next frame.
// Defer the call RequestCloseEditor() till next tick.
GEngine->DeferredCommands.Add( TEXT("CLOSE_SLATE_MAINFRAME") );
// Cannot exit right now.
return false;
}
else
{
// NORMAL EXIT PATH
// Unattented mode can always exit.
if (FApp::IsUnattended())
{
return true;
}
// We can't close if lightmass is currently building
if (GUnrealEd->WarnIfLightingBuildIsCurrentlyRunning()) {return false;}
bool bOkToExit = true;
// Check if level Mode is open this does PostEditMove processing on actors when it closes so need to do this first before save dialog
if( GLevelEditorModeTools().IsModeActive( FBuiltinEditorModes::EM_Level ) ||
GLevelEditorModeTools().IsModeActive( FBuiltinEditorModes::EM_StreamingLevel) )
{
GLevelEditorModeTools().DeactivateMode(FBuiltinEditorModes::EM_Level);
GLevelEditorModeTools().DeactivateMode(FBuiltinEditorModes::EM_StreamingLevel);
bOkToExit = false;
}
// Can we close all the major tabs? They have sub-editors in them that might want to not close
{
// Ignore the LevelEditor tab; it invoked this function in the first place.
TSet< TSharedRef<SDockTab> > TabsToIgnore;
if ( MainTabPtr.IsValid() )
{
TabsToIgnore.Add( MainTabPtr.Pin().ToSharedRef() );
}
bOkToExit = bOkToExit && FGlobalTabmanager::Get()->CanCloseManager(TabsToIgnore);
}
// Prompt for save and quit only if we did not launch a gameless rocket exe or are in demo mode
if ( FApp::HasGameName() && !GIsDemoMode )
{
// Prompt the user to save packages/maps.
bool bHadPackagesToSave = false;
{
const bool bPromptUserToSave = true;
const bool bSaveMapPackages = true;
const bool bSaveContentPackages = true;
const bool bFastSave = false;
const bool bNotifyNoPackagesSaved = false;
const bool bCanBeDeclined = true;
bOkToExit = bOkToExit && FEditorFileUtils::SaveDirtyPackages(bPromptUserToSave, bSaveMapPackages, bSaveContentPackages, bFastSave, bNotifyNoPackagesSaved, bCanBeDeclined, &bHadPackagesToSave);
}
// If there were packages to save, or switching project, then the user already had a chance to bail out of exiting.
if ( !bOkToExit && !bHadPackagesToSave && FUnrealEdMisc::Get().GetPendingProjectName().IsEmpty() )
{
FUnrealEdMisc::Get().ClearPendingProjectName();
FUnrealEdMisc::Get().AllowSavingLayoutOnClose(true);
FUnrealEdMisc::Get().ForceDeletePreferences(false);
FUnrealEdMisc::Get().ClearConfigRestoreFilenames();
}
}
return bOkToExit;
}
}
void CloseRootWindowOverride( const TSharedRef<SWindow>& WindowBeingClosed )
{
if (CanCloseEditor())
{
ShutDownEditor();
}
}
/**
* Method that handles the generation of the mainframe, given the window it resides in,
* and a string which determines the initial layout of its primary dock area.
*/
void OnMainFrameGenerated( const TSharedPtr<SDockTab>& MainTab, const TSharedRef<SWindow>& InRootWindow )
{
TSharedRef<FGlobalTabmanager> GlobalTabManager = FGlobalTabmanager::Get();
if (MainTab.IsValid())
{
GlobalTabManager->SetMainTab(MainTab.ToSharedRef());
}
// Persistent layouts should get stored using the specified method.
GlobalTabManager->SetOnPersistLayout(FTabManager::FOnPersistLayout::CreateRaw(this, &FMainFrameHandler::HandleTabManagerPersistLayout));
const bool bIncludeGameName = true;
GlobalTabManager->SetApplicationTitle( StaticGetApplicationTitle( bIncludeGameName ) );
InRootWindow->SetRequestDestroyWindowOverride( FRequestDestroyWindowOverride::CreateRaw( this, &FMainFrameHandler::CloseRootWindowOverride ) );
MainTabPtr = MainTab;
RootWindowPtr = InRootWindow;
EnableTabClosedDelegate();
}
/**
* Shows the main frame window. Call this after you've setup initial layouts to reveal the window
*
* @param bStartImmersive True to force a main frame viewport into immersive mode
* @param bStartPIE True to start a PIE session right away
*/
void ShowMainFrameWindow(TSharedRef<SWindow> Window, const bool bStartImmersive, const bool bStartPIE) const
{
// Make sure viewport windows are maximized/immersed if they need to be
FLevelEditorModule& LevelEditor = FModuleManager::GetModuleChecked< FLevelEditorModule >( TEXT( "LevelEditor" ) );
if( bStartPIE )
{
// Kick off an immersive PIE session immediately!
if( bStartImmersive )
{
// When in immersive play in editor, toggle game view on the active viewport
const bool bForceGameView = true;
// Start level viewport initially in immersive mode
LevelEditor.GoImmersiveWithActiveLevelViewport( bForceGameView );
}
LevelEditor.StartPlayInEditorSession();
Window->ShowWindow();
// Ensure the window is at the front or else we could end up capturing and locking the mouse to a window that isn't visible
bool bForceWindowToFront = true;
Window->BringToFront( bForceWindowToFront );
// Need to register after the window is shown or else we cant capture the mouse
TSharedPtr<ILevelViewport> Viewport = LevelEditor.GetFirstActiveViewport();
Viewport->RegisterGameViewportIfPIE();
}
else
{
if( bStartImmersive )
{
// When in immersive play in editor, toggle game view on the active viewport
const bool bForceGameView = true;
// Start level viewport initially in immersive mode
LevelEditor.GoImmersiveWithActiveLevelViewport( bForceGameView );
}
// Show the window!
Window->ShowWindow();
if( bStartImmersive )
{
// Ensure the window is at the front or else we could end up capturing and locking the mouse to a window that isn't visible
bool bForceWindowToFront = true;
Window->BringToFront( bForceWindowToFront );
}
else
{
// Focus the level editor viewport
LevelEditor.FocusViewport();
// Restore any assets we had open. Note we don't do this on immersive PIE as its annoying to the user.
FAssetEditorManager::Get().RequestRestorePreviouslyOpenAssets();
}
}
}
/** Gets the parent window of the mainframe */
TSharedPtr<SWindow> GetParentWindow() const
{
return RootWindowPtr.Pin();
}
/** Sets the reference to the main tab */
void SetMainTab(const TSharedRef<SDockTab>& MainTab)
{
MainTabPtr = MainTab;
}
/** Enables the delegate responsible for shutting down the editor when the main tab is closed */
void EnableTabClosedDelegate();
/** Disables the delegate responsible for shutting down the editor when the main tab is closed */
void DisableTabClosedDelegate();
private:
// Callback for persisting the Level Editor's layout.
void HandleTabManagerPersistLayout( const TSharedRef<FTabManager::FLayout>& LayoutToSave )
{
FLayoutSaveRestore::SaveToConfig(GEditorLayoutIni, LayoutToSave);
}
private:
/** Editor main frame window */
TWeakPtr<SDockTab> MainTabPtr;
/** The window that all of the editor is parented to. */
TWeakPtr<SWindow> RootWindowPtr;
};