Files
UnrealEngineUWP/Engine/Source/Developer/OutputLog/Private/OutputLogModule.cpp
bryan sefcik a3dddc6630 Pass 1 on Developer include fixes:
Removed redundant private include paths from build.cs files.
Fixed include paths to be relative to the private or public folders.
Hid or removed includes that reached into other private module folders.
Updated PublicInclude paths when necessary.

#jira
#preflight 631e281694758d0bf2ea1399

[CL 21960082 by bryan sefcik in ue5-main branch]
2022-09-11 18:32:18 -04:00

379 lines
11 KiB
C++

// Copyright Epic Games, Inc. All Rights Reserved.
#include "OutputLogModule.h"
#include "Modules/ModuleManager.h"
#include "Framework/Application/SlateApplication.h"
#include "Textures/SlateIcon.h"
#include "Framework/Docking/TabManager.h"
#include "Styling/AppStyle.h"
#include "OutputLogCreationParams.h"
#include "SDebugConsole.h"
#include "SOutputLog.h"
#include "SDeviceOutputLog.h"
#include "Widgets/Docking/SDockTab.h"
#include "Misc/ConfigCacheIni.h"
#if WITH_EDITOR
#include "Editor.h"
#include "ISettingsModule.h"
#endif
#if WITH_EDITOR || (IS_PROGRAM && WITH_UNREAL_DEVELOPER_TOOLS)
#include "WorkspaceMenuStructure.h"
#include "WorkspaceMenuStructureModule.h"
#include "OutputLogSettings.h"
#endif
#include "Internationalization/Internationalization.h"
#include "OutputLogStyle.h"
#if WITH_EDITOR
#include "StatusBarSubsystem.h"
#endif
IMPLEMENT_MODULE(FOutputLogModule, OutputLog);
namespace OutputLogModule
{
static const FName OutputLogTabName = FName(TEXT("OutputLog"));
static const FName DeviceOutputLogTabName = FName(TEXT("DeviceOutputLog"));
}
/** This class is to capture all log output even if the log window is closed */
class FOutputLogHistory : public FOutputDevice
{
public:
FOutputLogHistory()
{
GLog->AddOutputDevice(this);
GLog->SerializeBacklog(this);
}
~FOutputLogHistory()
{
// At shutdown, GLog may already be null
if (GLog != NULL)
{
GLog->RemoveOutputDevice(this);
}
}
/** Gets all captured messages */
const TArray< TSharedPtr<FOutputLogMessage> >& GetMessages() const
{
return Messages;
}
protected:
virtual void Serialize(const TCHAR* V, ELogVerbosity::Type Verbosity, const class FName& Category) override
{
// Capture all incoming messages and store them in history
SOutputLog::CreateLogMessages(V, Verbosity, Category, Messages);
}
private:
/** All log messsges since this module has been started */
TArray< TSharedPtr<FOutputLogMessage> > Messages;
};
TSharedRef<SDockTab> FOutputLogModule::SpawnOutputLogTab(const FSpawnTabArgs& Args)
{
TSharedRef<SOutputLog> NewLog = SNew(SOutputLog, false).Messages(OutputLogHistory->GetMessages());
OutputLog = NewLog;
TSharedRef<SDockTab> NewTab = SNew(SDockTab)
.TabRole(ETabRole::NomadTab)
.Label(NSLOCTEXT("OutputLog", "TabTitle", "Output Log"))
[
NewLog
];
OutputLogTab = NewTab;
return NewTab;
}
TSharedRef<SDockTab> FOutputLogModule::SpawnDeviceOutputLogTab(const FSpawnTabArgs& Args)
{
return SNew(SDockTab)
.TabRole(ETabRole::NomadTab)
.Label(NSLOCTEXT("OutputLog", "DeviceTabTitle", "Device Output Log"))
[
SNew(SDeviceOutputLog)
];
}
void FOutputLogModule::StartupModule()
{
FOutputLogStyle::Get();
#if WITH_EDITOR
ISettingsModule* SettingsModule = FModuleManager::GetModulePtr<ISettingsModule>("Settings");
if (SettingsModule)
{
SettingsModule->RegisterSettings("Editor", "General", "Output Log",
NSLOCTEXT("OutputLog", "OutputLogSettingsName", "Output Log"),
NSLOCTEXT("OutputLog", "OutputLogSettingsDescription", "Set up preferences for the Output Log appearance and workflow."),
GetMutableDefault<UOutputLogSettings>()
);
}
FEditorDelegates::BeginPIE.AddRaw(this, &FOutputLogModule::ClearOnPIE);
#endif
#if WITH_EDITOR || (IS_PROGRAM && WITH_UNREAL_DEVELOPER_TOOLS)
FGlobalTabmanager::Get()->RegisterNomadTabSpawner(OutputLogModule::OutputLogTabName, FOnSpawnTab::CreateRaw(this, &FOutputLogModule::SpawnOutputLogTab))
.SetDisplayName(NSLOCTEXT("OutputLog", "OutputLogTab", "Output Log"))
.SetTooltipText(NSLOCTEXT("OutputLog", "OutputLogTooltipText", "Open the Output Log tab."))
.SetGroup(WorkspaceMenu::GetMenuStructure().GetDeveloperToolsLogCategory())
.SetIcon(FSlateIcon(FOutputLogStyle::Get().GetStyleSetName(), "Log.TabIcon"));
FGlobalTabmanager::Get()->RegisterNomadTabSpawner(OutputLogModule::DeviceOutputLogTabName, FOnSpawnTab::CreateRaw(this, &FOutputLogModule::SpawnDeviceOutputLogTab))
.SetDisplayName(NSLOCTEXT("OutputLog", "DeviceOutputLogTab", "Device Output Log"))
.SetTooltipText(NSLOCTEXT("OutputLog", "DeviceOutputLogTooltipText", "Open the Device Output Log tab."))
.SetGroup(WorkspaceMenu::GetMenuStructure().GetDeveloperToolsLogCategory())
.SetIcon(FSlateIcon(FOutputLogStyle::Get().GetStyleSetName(), "Log.TabIcon"));
#endif
OutputLogHistory = MakeShareable(new FOutputLogHistory);
}
void FOutputLogModule::ShutdownModule()
{
#if WITH_EDITOR || (IS_PROGRAM && WITH_UNREAL_DEVELOPER_TOOLS)
if (FSlateApplication::IsInitialized())
{
FGlobalTabmanager::Get()->UnregisterNomadTabSpawner(OutputLogModule::OutputLogTabName);
FGlobalTabmanager::Get()->UnregisterNomadTabSpawner(OutputLogModule::DeviceOutputLogTabName);
}
#endif
#if WITH_EDITOR
FEditorDelegates::BeginPIE.RemoveAll(this);
#endif
FOutputLogStyle::Shutdown();
OutputLogHistory.Reset();
}
FOutputLogModule& FOutputLogModule::Get()
{
static const FName OutputLog("OutputLog");
return FModuleManager::Get().LoadModuleChecked<FOutputLogModule>(OutputLog);
}
TSharedRef<SWidget> FOutputLogModule::MakeConsoleInputBox(TSharedPtr<SMultiLineEditableTextBox>& OutExposedEditableTextBox, const FSimpleDelegate& OnCloseConsole, const FSimpleDelegate& OnConsoleCommandExecuted) const
{
TSharedRef<SConsoleInputBox> NewConsoleInputBox =
SNew(SConsoleInputBox)
.OnCloseConsole(OnCloseConsole)
.OnConsoleCommandExecuted(OnConsoleCommandExecuted);
OutExposedEditableTextBox = NewConsoleInputBox->GetEditableTextBox();
return NewConsoleInputBox;
}
TSharedRef<SWidget> FOutputLogModule::MakeOutputLogDrawerWidget(const FSimpleDelegate& OnCloseConsole)
{
TSharedPtr<SOutputLog> OutputLogDrawerPinned = OutputLogDrawer.Pin();
if (!OutputLogDrawerPinned.IsValid())
{
OutputLogDrawerPinned =
SNew(SOutputLog, true)
.OnCloseConsole(OnCloseConsole)
.Messages(OutputLogHistory->GetMessages());
OutputLogDrawer = OutputLogDrawerPinned;
}
return OutputLogDrawerPinned.ToSharedRef();
}
TSharedRef<SWidget> FOutputLogModule::MakeOutputLogWidget(const FOutputLogCreationParams& Params)
{
return SNew(SOutputLog, Params.bCreateDockInLayoutButton)
.OnCloseConsole(Params.OnCloseConsole)
.Messages(OutputLogHistory->GetMessages())
.SettingsMenuFlags(Params.SettingsMenuCreationFlags)
.DefaultCategorySelection(Params.DefaultCategorySelection)
.AllowInitialLogCategory(Params.AllowAsInitialLogCategory);
}
void FOutputLogModule::ToggleDebugConsoleForWindow(const TSharedRef<SWindow>& Window, const EDebugConsoleStyle::Type InStyle, const FDebugConsoleDelegates& DebugConsoleDelegates)
{
bool bShouldOpen = true;
// Close an existing console box, if there is one
TSharedPtr< SWidget > PinnedDebugConsole(DebugConsole.Pin());
if (PinnedDebugConsole.IsValid())
{
// If the console is already open close it unless it is in a different window. In that case reopen it on that window
bShouldOpen = false;
TSharedPtr< SWindow > WindowForExistingConsole = FSlateApplication::Get().FindWidgetWindow(PinnedDebugConsole.ToSharedRef());
if (WindowForExistingConsole.IsValid())
{
if (PreviousKeyboardFocusedWidget.IsValid())
{
FSlateApplication::Get().SetKeyboardFocus(PreviousKeyboardFocusedWidget.Pin());
PreviousKeyboardFocusedWidget.Reset();
}
WindowForExistingConsole->RemoveOverlaySlot(PinnedDebugConsole.ToSharedRef());
DebugConsole.Reset();
}
if (WindowForExistingConsole != Window)
{
// Console is being opened on another window
bShouldOpen = true;
}
}
TSharedPtr<SDockTab> ActiveTab = FGlobalTabmanager::Get()->GetActiveTab();
if (ActiveTab.IsValid() && ActiveTab == OutputLogTab)
{
FGlobalTabmanager::Get()->DrawAttention(ActiveTab.ToSharedRef());
bShouldOpen = false;
}
if (bShouldOpen)
{
const EDebugConsoleStyle::Type DebugConsoleStyle = InStyle;
TSharedRef< SDebugConsole > DebugConsoleRef = SNew(SDebugConsole, DebugConsoleStyle, this, &DebugConsoleDelegates);
DebugConsole = DebugConsoleRef;
const int32 MaximumZOrder = MAX_int32;
Window->AddOverlaySlot(MaximumZOrder)
.VAlign(VAlign_Bottom)
.HAlign(HAlign_Center)
.Padding(10.0f)
[
DebugConsoleRef
];
PreviousKeyboardFocusedWidget = FSlateApplication::Get().GetKeyboardFocusedWidget();
// Force keyboard focus
DebugConsoleRef->SetFocusToEditableText();
}
}
void FOutputLogModule::CloseDebugConsole()
{
TSharedPtr< SWidget > PinnedDebugConsole(DebugConsole.Pin());
if (PinnedDebugConsole.IsValid())
{
TSharedPtr< SWindow > WindowForExistingConsole = FSlateApplication::Get().FindWidgetWindow(PinnedDebugConsole.ToSharedRef());
if (WindowForExistingConsole.IsValid())
{
WindowForExistingConsole->RemoveOverlaySlot(PinnedDebugConsole.ToSharedRef());
DebugConsole.Reset();
if (TSharedPtr<SWidget> PreviousKeyboardFocusedWidgetPinned = PreviousKeyboardFocusedWidget.Pin())
{
FSlateApplication::Get().SetKeyboardFocus(PreviousKeyboardFocusedWidgetPinned);
PreviousKeyboardFocusedWidget.Reset();
}
}
}
}
void FOutputLogModule::ClearOnPIE(const bool bIsSimulating)
{
bool bClearOnPIEEnabled = false;
GConfig->GetBool(TEXT("/Script/UnrealEd.EditorPerProjectUserSettings"), TEXT("bEnableOutputLogClearOnPIE"), bClearOnPIEEnabled, GEditorPerProjectIni);
if (bClearOnPIEEnabled)
{
if (TSharedPtr<SOutputLog> OutputLogPinned = OutputLog.Pin())
{
if (OutputLogPinned->CanClearLog())
{
OutputLogPinned->OnClearLog();
}
}
if (TSharedPtr<SOutputLog> OutputLogPinned = OutputLogDrawer.Pin())
{
if (OutputLogPinned->CanClearLog())
{
OutputLogPinned->OnClearLog();
}
}
}
}
void FOutputLogModule::FocusOutputLogConsoleBox(const TSharedRef<SWidget> OutputLogToFocus)
{
if (OutputLog == OutputLogToFocus)
{
OutputLog.Pin()->FocusConsoleCommandBox();
}
else if (OutputLogDrawer == OutputLogToFocus)
{
OutputLogDrawer.Pin()->FocusConsoleCommandBox();
}
}
const TSharedPtr<SWidget> FOutputLogModule::GetOutputLog() const
{
return OutputLog.Pin();
}
void FOutputLogModule::FocusOutputLog()
{
// 1. Output log tab is open but not active.
if (OutputLog.IsValid())
{
OutputLogTab.Pin()->DrawAttention();
}
#if WITH_EDITOR
// 2. Output log tab isn't open and the window directly behind the notification window has a status bar, then open Output Log Drawer.
else if (GEditor->GetEditorSubsystem<UStatusBarSubsystem>()->ActiveWindowBehindNotificationHasStatusBar())
{
TSharedRef<SWindow> ParentWindow = FSlateApplication::Get().GetActiveTopLevelRegularWindow().ToSharedRef();
// try toggle the console to open the Output Log Drawer
if (GEditor->GetEditorSubsystem<UStatusBarSubsystem>()->ToggleDebugConsole(ParentWindow, true))
{
OutputLogDrawer.Pin()->FocusConsoleCommandBox();
}
// if unable to open the drawer, invoke a new Output Log tab.
else
{
OpenOutputLog();
OutputLogTab.Pin()->DrawAttention();
}
}
#endif
// 3. The parent window has no status bar, then invoke a new Output Log tab.
else
{
OpenOutputLog();
OutputLogTab.Pin()->DrawAttention();
}
}
void FOutputLogModule::UpdateOutputLogFilter(const TArray<FName>& CategoriesToShow, TOptional<bool> bShowErrors, TOptional<bool> bShowWarnings, TOptional<bool> bShowLogs)
{
if (TSharedPtr<SOutputLog> SharedOutputLog = OutputLog.Pin())
{
SharedOutputLog->UpdateOutputLogFilter(CategoriesToShow, bShowErrors, bShowWarnings, bShowLogs);
}
}
void FOutputLogModule::OpenOutputLog() const
{
FGlobalTabmanager::Get()->TryInvokeTab(OutputLogModule::OutputLogTabName);
}
bool FOutputLogModule::ShouldCycleToOutputLogDrawer() const
{
return GetDefault<UOutputLogSettings>()->bCycleToOutputLogDrawer;
}