// Copyright 1998-2015 Epic Games, Inc. All Rights Reserved. #include "LogVisualizer.h" #include "SDockTab.h" #include "VisualLogger/VisualLogger.h" #include "VisualLoggerRenderingActor.h" #include "VisualLoggerCanvasRenderer.h" #include "DesktopPlatformModule.h" #include "MainFrame.h" #include "VisualLoggerCameraController.h" #if WITH_EDITOR # include "Editor/UnrealEd/Public/EditorComponents.h" # include "Editor/UnrealEd/Public/EditorReimportHandler.h" # include "Editor/UnrealEd/Public/TexAlignTools.h" # include "Editor/UnrealEd/Public/TickableEditorObject.h" # include "UnrealEdClasses.h" # include "Editor/UnrealEd/Public/Editor.h" # include "Editor/UnrealEd/Public/EditorViewportClient.h" #endif #include "ISettingsModule.h" #include "VisualLogger/VisualLoggerBinaryFileDevice.h" #define LOCTEXT_NAMESPACE "SVisualLogger" /* Local constants *****************************************************************************/ static const FName ToolbarTabId("Toolbar"); static const FName FiltersTabId("Filters"); static const FName MainViewTabId("MainView"); static const FName LogsListTabId("LogsList"); static const FName StatusViewTabId("StatusView"); namespace LogVisualizer { static const FString LogFileDescription = LOCTEXT("FileTypeDescription", "Visual Log File").ToString(); static const FString LoadFileTypes = FString::Printf(TEXT("%s (*.vlog;*.%s)|*.vlog;*.%s"), *LogFileDescription, VISLOG_FILENAME_EXT, VISLOG_FILENAME_EXT); static const FString SaveFileTypes = FString::Printf(TEXT("%s (*.%s)|*.%s"), *LogFileDescription, VISLOG_FILENAME_EXT, VISLOG_FILENAME_EXT); } struct FVisualLoggerInterface : public IVisualLoggerInterface { FVisualLoggerInterface(TSharedPtr InVisualLogger) : VisualLogger(InVisualLogger) { } virtual ~FVisualLoggerInterface() { } virtual bool HasValidCategories(TArray Categories) override { for (const auto& CurrentCategory : Categories) { if (VisualLogger.Pin()->GetVisualLoggerFilters()->IsFilterEnabled(CurrentCategory.CategoryName.ToString(), CurrentCategory.Verbosity)) { return true; } } return false; } bool IsValidCategory(const FString& InCategoryName, TEnumAsByte Verbosity) { return VisualLogger.Pin()->GetVisualLoggerFilters()->IsFilterEnabled(InCategoryName, Verbosity); } bool IsValidCategory(const FString& InGraphName, const FString& InDataName, TEnumAsByte Verbosity = ELogVerbosity::All) { return VisualLogger.Pin()->GetVisualLoggerFilters()->IsFilterEnabled(InGraphName, InDataName, Verbosity); } protected: TWeakPtr VisualLogger; }; SVisualLogger::FVisualLoggerDevice::FVisualLoggerDevice(SVisualLogger* InOwner) :Owner(InOwner) { } SVisualLogger::FVisualLoggerDevice::~FVisualLoggerDevice() { } void SVisualLogger::FVisualLoggerDevice::Serialize(const class UObject* LogOwner, FName OwnerName, FName OwnerClassName, const FVisualLogEntry& LogEntry) { if (Owner == NULL) { return; } UWorld* World = FLogVisualizer::Get().GetWorld(); if (LastWorld.Get() != World) { Owner->OnNewWorld(LastWorld.Get()); LastWorld = World; } Owner->OnNewLogEntry(FVisualLogDevice::FVisualLogEntryItem(OwnerName, OwnerClassName, LogEntry)); } /* SMessagingDebugger constructors *****************************************************************************/ SVisualLogger::SVisualLogger() : SCompoundWidget(), CommandList(MakeShareable(new FUICommandList)) { InternalDevice = MakeShareable(new FVisualLoggerDevice(this)); FVisualLogger::Get().AddDevice(InternalDevice.Get()); } SVisualLogger::~SVisualLogger() { UWorld* World = NULL; #if WITH_EDITOR ULogVisualizerSettings* Settings = ULogVisualizerSettings::StaticClass()->GetDefaultObject(); if (Settings->bPresistentFilters) { Settings->PresistentPresets = Settings->CurrentPresets; } else { Settings->PresistentPresets = Settings->CurrentPresets = FFiltersPreset(); } Settings->SaveConfig(); UEditorEngine *EEngine = Cast(GEngine); if (GIsEditor && EEngine != NULL) { // lets use PlayWorld during PIE/Simulate and regular world from editor otherwise, to draw debug information World = EEngine->PlayWorld != NULL ? EEngine->PlayWorld : EEngine->GetEditorWorldContext().World(); } else #endif if (!GIsEditor) { World = GEngine->GetWorld(); } if (World == NULL) { World = GWorld; } if (World) { for (TActorIterator It(World); It; ++It) { World->DestroyActor(*It); } } UDebugDrawService::Unregister(DrawOnCanvasDelegateHandle); VisualLoggerCanvasRenderer.Reset(); FVisualLogger::Get().RemoveDevice(InternalDevice.Get()); InternalDevice.Reset(); VisualLoggerInterface.Reset(); } /* SMessagingDebugger interface *****************************************************************************/ void SVisualLogger::Construct(const FArguments& InArgs, const TSharedRef& ConstructUnderMajorTab, const TSharedPtr& ConstructUnderWindow) { FLogVisualizer::Get().SetCurrentVisualizer(SharedThis(this)); ////////////////////////////////////////////////////////////////////////// // Visual Logger Events FLogVisualizer::Get().GetVisualLoggerEvents().OnItemSelectionChanged = FOnItemSelectionChanged::CreateRaw(this, &SVisualLogger::OnItemSelectionChanged); FLogVisualizer::Get().GetVisualLoggerEvents().OnFiltersChanged = FOnFiltersChanged::CreateRaw(this, &SVisualLogger::OnFiltersChanged); FLogVisualizer::Get().GetVisualLoggerEvents().OnObjectSelectionChanged = FOnObjectSelectionChanged::CreateRaw(this, &SVisualLogger::OnObjectSelectionChanged); ////////////////////////////////////////////////////////////////////////// // Visual Logger Interface VisualLoggerInterface = MakeShareable(new FVisualLoggerInterface(SharedThis(this))); FLogVisualizer::Get().SetVisualLoggerInterface(VisualLoggerInterface); ////////////////////////////////////////////////////////////////////////// // Command Action Lists const FVisualLoggerCommands& Commands = FVisualLoggerCommands::Get(); FUICommandList& ActionList = *CommandList; ULogVisualizerSettings* Settings = ULogVisualizerSettings::StaticClass()->GetDefaultObject(); Settings->CurrentPresets = Settings->bPresistentFilters ? Settings->PresistentPresets : FFiltersPreset(); ActionList.MapAction(Commands.StartRecording, FExecuteAction::CreateRaw(this, &SVisualLogger::HandleStartRecordingCommandExecute), FCanExecuteAction::CreateRaw(this, &SVisualLogger::HandleStartRecordingCommandCanExecute), FIsActionChecked(), FIsActionButtonVisible::CreateRaw(this, &SVisualLogger::HandleStartRecordingCommandIsVisible)); ActionList.MapAction(Commands.StopRecording, FExecuteAction::CreateRaw(this, &SVisualLogger::HandleStopRecordingCommandExecute), FCanExecuteAction::CreateRaw(this, &SVisualLogger::HandleStopRecordingCommandCanExecute), FIsActionChecked(), FIsActionButtonVisible::CreateRaw(this, &SVisualLogger::HandleStopRecordingCommandIsVisible)); ActionList.MapAction(Commands.Pause, FExecuteAction::CreateRaw(this, &SVisualLogger::HandlePauseCommandExecute), FCanExecuteAction::CreateRaw(this, &SVisualLogger::HandlePauseCommandCanExecute), FIsActionChecked(), FIsActionButtonVisible::CreateRaw(this, &SVisualLogger::HandlePauseCommandIsVisible)); ActionList.MapAction(Commands.Resume, FExecuteAction::CreateRaw(this, &SVisualLogger::HandleResumeCommandExecute), FCanExecuteAction::CreateRaw(this, &SVisualLogger::HandleResumeCommandCanExecute), FIsActionChecked(), FIsActionButtonVisible::CreateRaw(this, &SVisualLogger::HandleResumeCommandIsVisible)); ActionList.MapAction(Commands.LoadFromVLog, FExecuteAction::CreateRaw(this, &SVisualLogger::HandleLoadCommandExecute), FCanExecuteAction::CreateRaw(this, &SVisualLogger::HandleLoadCommandCanExecute), FIsActionChecked(), FIsActionButtonVisible::CreateRaw(this, &SVisualLogger::HandleLoadCommandCanExecute)); ActionList.MapAction(Commands.SaveToVLog, FExecuteAction::CreateRaw(this, &SVisualLogger::HandleSaveCommandExecute), FCanExecuteAction::CreateRaw(this, &SVisualLogger::HandleSaveCommandCanExecute), FIsActionChecked(), FIsActionButtonVisible::CreateRaw(this, &SVisualLogger::HandleSaveCommandCanExecute)); ActionList.MapAction(Commands.FreeCamera, FExecuteAction::CreateRaw(this, &SVisualLogger::HandleCameraCommandExecute), FCanExecuteAction::CreateRaw(this, &SVisualLogger::HandleCameraCommandCanExecute), FIsActionChecked::CreateRaw(this, &SVisualLogger::HandleCameraCommandIsChecked), FIsActionButtonVisible::CreateRaw(this, &SVisualLogger::HandleCameraCommandCanExecute)); ActionList.MapAction(Commands.ToggleGraphs, FExecuteAction::CreateLambda([](){bool& bEnableGraphsVisualization = ULogVisualizerSessionSettings::StaticClass()->GetDefaultObject()->bEnableGraphsVisualization; bEnableGraphsVisualization = !bEnableGraphsVisualization; }), FCanExecuteAction(), FIsActionChecked::CreateLambda([]()->bool{return ULogVisualizerSessionSettings::StaticClass()->GetDefaultObject()->bEnableGraphsVisualization; }), FIsActionButtonVisible()); ActionList.MapAction(Commands.ResetData, FExecuteAction::CreateRaw(this, &SVisualLogger::ResetData), FCanExecuteAction::CreateRaw(this, &SVisualLogger::HandleSaveCommandCanExecute), FIsActionChecked(), FIsActionButtonVisible::CreateRaw(this, &SVisualLogger::HandleSaveCommandCanExecute)); ActionList.MapAction( Commands.MoveCursorLeft, FExecuteAction::CreateRaw(this, &SVisualLogger::OnMoveCursorLeftCommand)); ActionList.MapAction( Commands.MoveCursorRight, FExecuteAction::CreateRaw(this, &SVisualLogger::OnMoveCursorRightCommand)); // Tab Spawners TabManager = FGlobalTabmanager::Get()->NewTabManager(ConstructUnderMajorTab); TSharedRef AppMenuGroup = TabManager->AddLocalWorkspaceMenuCategory(LOCTEXT("VisualLoggerGroupName", "Visual Logger")); TabManager->RegisterTabSpawner(ToolbarTabId, FOnSpawnTab::CreateRaw(this, &SVisualLogger::HandleTabManagerSpawnTab, ToolbarTabId)) .SetDisplayName(LOCTEXT("ToolbarTabTitle", "Toolbar")) .SetGroup(AppMenuGroup) .SetIcon(FSlateIcon(FLogVisualizerStyle::Get().GetStyleSetName(), "ToolbarTabIcon")); TabManager->RegisterTabSpawner(FiltersTabId, FOnSpawnTab::CreateRaw(this, &SVisualLogger::HandleTabManagerSpawnTab, FiltersTabId)) .SetDisplayName(LOCTEXT("FiltersTabTitle", "Filters")) .SetGroup(AppMenuGroup) .SetIcon(FSlateIcon(FLogVisualizerStyle::Get().GetStyleSetName(), "FiltersTabIcon")); TabManager->RegisterTabSpawner(MainViewTabId, FOnSpawnTab::CreateRaw(this, &SVisualLogger::HandleTabManagerSpawnTab, MainViewTabId)) .SetDisplayName(LOCTEXT("MainViewTabTitle", "MainView")) .SetGroup(AppMenuGroup) .SetIcon(FSlateIcon(FLogVisualizerStyle::Get().GetStyleSetName(), "MainViewTabIcon")); TabManager->RegisterTabSpawner(LogsListTabId, FOnSpawnTab::CreateRaw(this, &SVisualLogger::HandleTabManagerSpawnTab, LogsListTabId)) .SetDisplayName(LOCTEXT("LogsListTabTitle", "LogsList")) .SetGroup(AppMenuGroup) .SetIcon(FSlateIcon(FLogVisualizerStyle::Get().GetStyleSetName(), "LogsListTabIcon")); TabManager->RegisterTabSpawner(StatusViewTabId, FOnSpawnTab::CreateRaw(this, &SVisualLogger::HandleTabManagerSpawnTab, StatusViewTabId)) .SetDisplayName(LOCTEXT("StatusViewTabTitle", "StatusView")) .SetGroup(AppMenuGroup) .SetIcon(FSlateIcon(FLogVisualizerStyle::Get().GetStyleSetName(), "StatusViewTabIcon")); // Default Layout const TSharedRef Layout = FTabManager::NewLayout("VisualLoggerLayout_v1.0") ->AddArea ( FTabManager::NewPrimaryArea() ->SetOrientation(Orient_Vertical) ->Split ( FTabManager::NewStack() ->AddTab(ToolbarTabId, ETabState::OpenedTab) ->SetHideTabWell(true) ) ->Split ( FTabManager::NewStack() ->AddTab(FiltersTabId, ETabState::OpenedTab) ->SetHideTabWell(true) ) ->Split ( FTabManager::NewStack() ->AddTab(MainViewTabId, ETabState::OpenedTab) ->SetHideTabWell(true) ) ->Split ( FTabManager::NewSplitter() ->SetOrientation(Orient_Horizontal) ->SetSizeCoefficient(0.6f) ->Split ( FTabManager::NewStack() ->AddTab(StatusViewTabId, ETabState::OpenedTab) ->SetHideTabWell(true) ->SetSizeCoefficient(0.3f) ) ->Split ( FTabManager::NewStack() ->AddTab(LogsListTabId, ETabState::OpenedTab) ->SetHideTabWell(true) ->SetSizeCoefficient(0.7f) ) ) ); TabManager->SetOnPersistLayout(FTabManager::FOnPersistLayout::CreateRaw(this, &SVisualLogger::HandleTabManagerPersistLayout)); // Load the potentially previously saved new layout TSharedRef UserConfiguredNewLayout = FLayoutSaveRestore::LoadFromConfig(GEditorLayoutIni, Layout); TabManager->RestoreFrom(UserConfiguredNewLayout, TSharedPtr()); // Window Menu FMenuBarBuilder MenuBarBuilder = FMenuBarBuilder(TSharedPtr()); #if 0 //disabled File menu for now (SebaK) MenuBarBuilder.AddPullDownMenu( LOCTEXT("FileMenuLabel", "File"), FText::GetEmpty(), FNewMenuDelegate::CreateRaw(this, &SVisualLogger::FillFileMenu, TabManager), "File" ); #endif MenuBarBuilder.AddPullDownMenu( LOCTEXT("WindowMenuLabel", "Window"), FText::GetEmpty(), FNewMenuDelegate::CreateStatic(&SVisualLogger::FillWindowMenu, TabManager), "Window" ); MenuBarBuilder.AddMenuEntry( LOCTEXT("SettingsMenuLabel", "Settings"), FText::GetEmpty(), FSlateIcon(), FUIAction( FExecuteAction::CreateLambda( [this](){ ISettingsModule* SettingsModule = FModuleManager::GetModulePtr("Settings"); if (SettingsModule != nullptr) { SettingsModule->ShowViewer("Editor", "General", "VisualLogger"); } } )), "Settings" ); ChildSlot [ SNew(SVerticalBox) + SVerticalBox::Slot() .AutoHeight() [ MenuBarBuilder.MakeWidget() ] + SVerticalBox::Slot() .FillHeight(1.0f) [ TabManager->RestoreFrom(Layout, ConstructUnderWindow).ToSharedRef() ] ]; VisualLoggerCanvasRenderer = MakeShareable(new FVisualLoggerCanvasRenderer()); DrawOnCanvasDelegateHandle = UDebugDrawService::Register(TEXT("VisLog"), FDebugDrawDelegate::CreateRaw(VisualLoggerCanvasRenderer.Get(), &FVisualLoggerCanvasRenderer::DrawOnCanvas)); //UGameplayDebuggingComponent::OnDebuggingTargetChangedDelegate.AddSP(this, &SVisualLogger::SelectionChanged); } FReply SVisualLogger::OnKeyDown(const FGeometry& MyGeometry, const FKeyEvent& InKeyEvent) { FUICommandList& ActionList = *CommandList; return ActionList.ProcessCommandBindings(InKeyEvent) ? FReply::Handled() : FReply::Unhandled(); } void SVisualLogger::HandleMajorTabPersistVisualState() { // save any settings here } void SVisualLogger::HandleTabManagerPersistLayout(const TSharedRef& LayoutToSave) { FLayoutSaveRestore::SaveToConfig(GEditorLayoutIni, LayoutToSave); } void SVisualLogger::FillFileMenu(FMenuBuilder& MenuBuilder, const TSharedPtr TabManager) { MenuBuilder.BeginSection("LogFile", LOCTEXT("FileMenu", "Log File")); { MenuBuilder.AddMenuEntry(FVisualLoggerCommands::Get().LoadFromVLog); MenuBuilder.AddMenuEntry(FVisualLoggerCommands::Get().SaveToVLog); } MenuBuilder.EndSection(); MenuBuilder.BeginSection("LogFilters", LOCTEXT("FIlterMenu", "Log Filters")); { MenuBuilder.AddSubMenu( LOCTEXT("LoadPreset", "Load Preset"), LOCTEXT("LoadPresetTooltip", "Load filter's preset"), FNewMenuDelegate::CreateRaw(this, &SVisualLogger::FillLoadPresetMenu)); MenuBuilder.AddMenuEntry( LOCTEXT("SavePreset", "Save Preset"), LOCTEXT("SavePresetTooltip", "Save filter's setting as preset"), FSlateIcon(), FUIAction( FExecuteAction::CreateLambda( [this](){ } ))); } MenuBuilder.EndSection(); } void SVisualLogger::FillLoadPresetMenu(FMenuBuilder& MenuBuilder) { ULogVisualizerSettings* Settings = ULogVisualizerSettings::StaticClass()->GetDefaultObject(); MenuBuilder.BeginSection("FilterPresets", LOCTEXT("FilterPresets", "Presets")); for (auto& CurrentPreset : Settings->FilterPresets) { MenuBuilder.AddMenuEntry( FText::FromString(CurrentPreset.FilterName), LOCTEXT("LoadPresetTooltip", "Load filter's preset"), FSlateIcon(), FUIAction( FExecuteAction::CreateLambda([this, CurrentPreset](){ this->SetFiltersPreset(CurrentPreset); } )) ); } MenuBuilder.EndSection(); } void SVisualLogger::SetFiltersPreset(const struct FFiltersPreset& Preset) { OnFiltersSearchChanged(FText::FromString(Preset.DataFilter)); } void SVisualLogger::FillWindowMenu(FMenuBuilder& MenuBuilder, const TSharedPtr TabManager) { if (!TabManager.IsValid()) { return; } TabManager->PopulateLocalTabSpawnerMenu(MenuBuilder); } TSharedRef SVisualLogger::HandleTabManagerSpawnTab(const FSpawnTabArgs& Args, FName TabIdentifier) const { TSharedPtr TabWidget = SNullWidget::NullWidget; bool AutoSizeTab = false; if (TabIdentifier == ToolbarTabId) { TabWidget = SNew(SVisualLoggerToolbar, CommandList); AutoSizeTab = true; } else if (TabIdentifier == FiltersTabId) { TabWidget = SAssignNew(VisualLoggerFilters, SVisualLoggerFilters, CommandList); AutoSizeTab = true; } else if (TabIdentifier == MainViewTabId) { TabWidget = SAssignNew(MainView, SVisualLoggerView, CommandList).OnFiltersSearchChanged(this, &SVisualLogger::OnFiltersSearchChanged); AutoSizeTab = false; } else if (TabIdentifier == LogsListTabId) { TabWidget = SAssignNew(LogsList, SVisualLoggerLogsList, CommandList); AutoSizeTab = false; } else if (TabIdentifier == StatusViewTabId) { TabWidget = SAssignNew(StatusView, SVisualLoggerStatusView, CommandList); AutoSizeTab = false; } return SNew(SDockTab) .ShouldAutosize(AutoSizeTab) .TabRole(ETabRole::PanelTab) [ TabWidget.ToSharedRef() ]; } bool SVisualLogger::HandleStartRecordingCommandCanExecute() const { return !FVisualLogger::Get().IsRecording(); } void SVisualLogger::HandleStartRecordingCommandExecute() { FVisualLogger::Get().SetIsRecording(true); } bool SVisualLogger::HandleStartRecordingCommandIsVisible() const { return !FVisualLogger::Get().IsRecording(); } bool SVisualLogger::HandleStopRecordingCommandCanExecute() const { return FVisualLogger::Get().IsRecording(); } void SVisualLogger::HandleStopRecordingCommandExecute() { FVisualLogger::Get().SetIsRecording(false); UWorld* World = FLogVisualizer::Get().GetWorld(); if (AVisualLoggerCameraController::IsEnabled(World)) { AVisualLoggerCameraController::DisableCamera(World); } } bool SVisualLogger::HandleStopRecordingCommandIsVisible() const { return FVisualLogger::Get().IsRecording(); } bool SVisualLogger::HandlePauseCommandCanExecute() const { UWorld* World = FLogVisualizer::Get().GetWorld(); return FVisualLogger::Get().IsRecording() && World && !World->bPlayersOnly && !World->bPlayersOnlyPending; } void SVisualLogger::HandlePauseCommandExecute() { UWorld* World = FLogVisualizer::Get().GetWorld(); if (World != NULL) { World->bPlayersOnlyPending = true; } } bool SVisualLogger::HandlePauseCommandIsVisible() const { return HandlePauseCommandCanExecute(); } bool SVisualLogger::HandleResumeCommandCanExecute() const { UWorld* World = FLogVisualizer::Get().GetWorld(); return FVisualLogger::Get().IsRecording() && World && (World->bPlayersOnly || World->bPlayersOnlyPending); } void SVisualLogger::HandleResumeCommandExecute() { UWorld* World = FLogVisualizer::Get().GetWorld(); if (World != NULL) { World->bPlayersOnly = false; World->bPlayersOnlyPending = false; } } bool SVisualLogger::HandleResumeCommandIsVisible() const { return HandleResumeCommandCanExecute(); } bool SVisualLogger::HandleCameraCommandIsChecked() const { UWorld* World = FLogVisualizer::Get().GetWorld(); return World && AVisualLoggerCameraController::IsEnabled(World); } bool SVisualLogger::HandleCameraCommandCanExecute() const { UWorld* World = FLogVisualizer::Get().GetWorld(); return FVisualLogger::Get().IsRecording() && World && (World->bPlayersOnly || World->bPlayersOnlyPending) && World->IsPlayInEditor() && (GEditor && !GEditor->bIsSimulatingInEditor); } void SVisualLogger::HandleCameraCommandExecute() { UWorld* World = FLogVisualizer::Get().GetWorld(); if (AVisualLoggerCameraController::IsEnabled(World)) { AVisualLoggerCameraController::DisableCamera(World); } else { // switch debug cam on CameraController = AVisualLoggerCameraController::EnableCamera(World); if (CameraController.IsValid()) { //CameraController->OnActorSelected = ALogVisualizerCameraController::FActorSelectedDelegate::CreateSP(this, &SVisualLogger::CameraActorSelected); //CameraController->OnIterateLogEntries = ALogVisualizerCameraController::FLogEntryIterationDelegate::CreateSP(this, &SVisualLogger::IncrementCurrentLogIndex); } } } bool SVisualLogger::HandleLoadCommandCanExecute() const { return true; } void SVisualLogger::HandleLoadCommandExecute() { FArchive Ar; TArray RecordedLogs; TArray OpenFilenames; IDesktopPlatform* DesktopPlatform = FDesktopPlatformModule::Get(); bool bOpened = false; if (DesktopPlatform) { void* ParentWindowWindowHandle = NULL; IMainFrameModule& MainFrameModule = FModuleManager::LoadModuleChecked(TEXT("MainFrame")); const TSharedPtr& MainFrameParentWindow = MainFrameModule.GetParentWindow(); if (MainFrameParentWindow.IsValid() && MainFrameParentWindow->GetNativeWindow().IsValid()) { ParentWindowWindowHandle = MainFrameParentWindow->GetNativeWindow()->GetOSWindowHandle(); } const FString DefaultBrowsePath = FString::Printf(TEXT("%slogs/"), *FPaths::GameSavedDir()); bOpened = DesktopPlatform->OpenFileDialog( ParentWindowWindowHandle, LOCTEXT("OpenProjectBrowseTitle", "Open Project").ToString(), DefaultBrowsePath, TEXT(""), LogVisualizer::LoadFileTypes, EFileDialogFlags::None, OpenFilenames ); } if (bOpened && OpenFilenames.Num() > 0) { OnNewWorld(nullptr); for (int FilenameIndex = 0; FilenameIndex < OpenFilenames.Num(); ++FilenameIndex) { FString CurrentFileName = OpenFilenames[FilenameIndex]; const bool bIsBinaryFile = CurrentFileName.Find(TEXT(".bvlog")) != INDEX_NONE; if (bIsBinaryFile) { FArchive* FileAr = IFileManager::Get().CreateFileReader(*CurrentFileName); FVisualLoggerHelpers::Serialize(*FileAr, RecordedLogs); FileAr->Close(); delete FileAr; FileAr = NULL; for (FVisualLogDevice::FVisualLogEntryItem& CurrentItem : RecordedLogs) { OnNewLogEntry(CurrentItem); } } } } } bool SVisualLogger::HandleSaveCommandCanExecute() const { TArray > OutTimelines; MainView->GetTimelines(OutTimelines); return OutTimelines.Num() > 0; } void SVisualLogger::HandleSaveCommandExecute() { TArray > OutTimelines; MainView->GetTimelines(OutTimelines, true); if (OutTimelines.Num() == 0) { MainView->GetTimelines(OutTimelines); } if (OutTimelines.Num()) { // Prompt the user for the filenames TArray SaveFilenames; IDesktopPlatform* DesktopPlatform = FDesktopPlatformModule::Get(); bool bSaved = false; if (DesktopPlatform) { void* ParentWindowWindowHandle = NULL; IMainFrameModule& MainFrameModule = FModuleManager::LoadModuleChecked(TEXT("MainFrame")); const TSharedPtr& MainFrameParentWindow = MainFrameModule.GetParentWindow(); if (MainFrameParentWindow.IsValid() && MainFrameParentWindow->GetNativeWindow().IsValid()) { ParentWindowWindowHandle = MainFrameParentWindow->GetNativeWindow()->GetOSWindowHandle(); } const FString DefaultBrowsePath = FString::Printf(TEXT("%slogs/"), *FPaths::GameSavedDir()); bSaved = DesktopPlatform->SaveFileDialog( ParentWindowWindowHandle, LOCTEXT("NewProjectBrowseTitle", "Choose a project location").ToString(), DefaultBrowsePath, TEXT(""), LogVisualizer::SaveFileTypes, EFileDialogFlags::None, SaveFilenames ); } if (bSaved) { if (SaveFilenames.Num() > 0) { TArray FrameCache; for (auto CurrentItem : OutTimelines) { FrameCache.Append(CurrentItem->GetEntries()); } if (FrameCache.Num()) { FArchive* FileArchive = IFileManager::Get().CreateFileWriter(*SaveFilenames[0]); FVisualLoggerHelpers::Serialize(*FileArchive, FrameCache); FileArchive->Close(); delete FileArchive; FileArchive = NULL; } } } } } void SVisualLogger::ResetData() { if (MainView.IsValid()) { MainView->ResetData(); } if (VisualLoggerFilters.IsValid()) { VisualLoggerFilters->ResetData(); } if (LogsList.IsValid()) { LogsList->OnItemSelectionChanged(FVisualLogDevice::FVisualLogEntryItem()); } if (StatusView.IsValid()) { StatusView->OnItemSelectionChanged(FVisualLogDevice::FVisualLogEntryItem()); } if (VisualLoggerCanvasRenderer.IsValid()) { VisualLoggerCanvasRenderer->OnItemSelectionChanged(FVisualLogEntry()); VisualLoggerCanvasRenderer->ObjectSelectionChanged(NULL); } AVisualLoggerRenderingActor* HelperActor = Cast(FLogVisualizer::Get().GetVisualLoggerHelperActor()); if (HelperActor) { HelperActor->OnItemSelectionChanged(FVisualLogDevice::FVisualLogEntryItem()); HelperActor->ObjectSelectionChanged(NULL); } } void SVisualLogger::OnNewWorld(UWorld* NewWorld) { InternalDevice->SerLastWorld(NewWorld); if (ULogVisualizerSettings::StaticClass()->GetDefaultObject()->bResetDataWithNewSession) { ResetData(); } } void SVisualLogger::OnNewLogEntry(const FVisualLogDevice::FVisualLogEntryItem& Entry) { CollectNewCategories(Entry); MainView->OnNewLogEntry(Entry); } void SVisualLogger::CollectNewCategories(const FVisualLogDevice::FVisualLogEntryItem& Item) { TArray Categories; FVisualLoggerHelpers::GetCategories(Item.Entry, Categories); for (auto& CategoryAndVerbosity : Categories) { VisualLoggerFilters->AddFilter(CategoryAndVerbosity.CategoryName.ToString()); } TMap > OutCategories; FVisualLoggerHelpers::GetHistogramCategories(Item.Entry, OutCategories); for (const auto& CurrentCategory : OutCategories) { for (const auto& CurrentDataName : CurrentCategory.Value) { VisualLoggerFilters->AddFilter(CurrentCategory.Key, CurrentDataName); } } } void SVisualLogger::OnItemSelectionChanged(const FVisualLogDevice::FVisualLogEntryItem& EntryItem) { LogsList->OnItemSelectionChanged(EntryItem); StatusView->OnItemSelectionChanged(EntryItem); VisualLoggerCanvasRenderer->OnItemSelectionChanged(EntryItem.Entry); VisualLoggerFilters->OnItemSelectionChanged(EntryItem.Entry); AVisualLoggerRenderingActor* HelperActor = Cast(FLogVisualizer::Get().GetVisualLoggerHelperActor()); if (HelperActor) { HelperActor->OnItemSelectionChanged(EntryItem); } } void SVisualLogger::OnFiltersChanged() { LogsList->OnFiltersChanged(); MainView->OnFiltersChanged(); } void SVisualLogger::OnObjectSelectionChanged(TSharedPtr TimeLine) { VisualLoggerCanvasRenderer->ObjectSelectionChanged(TimeLine); AVisualLoggerRenderingActor* HelperActor = Cast(FLogVisualizer::Get().GetVisualLoggerHelperActor()); if (HelperActor) { HelperActor->ObjectSelectionChanged(TimeLine); } MainView->OnObjectSelectionChanged(TimeLine); FLogVisualizer::Get().OnObjectSelectionChanged(TimeLine); } void SVisualLogger::OnFiltersSearchChanged(const FText& Filter) { ULogVisualizerSettings::StaticClass()->GetDefaultObject()->CurrentPresets.DataFilter = Filter.ToString(); ULogVisualizerSettings::StaticClass()->GetDefaultObject()->SaveConfig(); if (VisualLoggerFilters.IsValid()) { VisualLoggerFilters->OnFiltersSearchChanged(Filter); } if (LogsList.IsValid()) { LogsList->OnFiltersSearchChanged(Filter); } if (MainView.IsValid()) { MainView->OnFiltersSearchChanged(Filter); } } void SVisualLogger::OnMoveCursorLeftCommand() { FLogVisualizer::Get().GotoNextItem(); } void SVisualLogger::OnMoveCursorRightCommand() { FLogVisualizer::Get().GotoPreviousItem(); } void SVisualLogger::GetTimelines(TArray >& TimeLines, bool bOnlySelectedOnes) { if (MainView.IsValid()) { MainView->GetTimelines(TimeLines, bOnlySelectedOnes); } } #undef LOCTEXT_NAMESPACE