Files
2025-05-18 13:04:45 +08:00

222 lines
7.2 KiB
C++

// Copyright Epic Games, Inc. All Rights Reserved.
#pragma once
#include "CoreMinimal.h"
#include "Logging/LogVerbosity.h"
#include "Misc/ScopeLock.h"
#include "SlateFwd.h"
#include "Templates/UniquePtr.h"
#include "Widgets/DeclarativeSyntaxSupport.h"
#include "Widgets/Input/SSearchBox.h"
#include "Widgets/SCompoundWidget.h"
#include "Widgets/Views/SListView.h"
// TraceInsightsCore
#include "InsightsCore/Common/Stopwatch.h"
// TraceInsights
#include "Insights/ViewModels/LogFilter.h"
#include "Insights/ViewModels/LogMessage.h"
class FMenuBuilder;
namespace UE::Insights::TimingProfiler { class STimingView; }
namespace UE::Insights
{
////////////////////////////////////////////////////////////////////////////////////////////////////
namespace LogViewColumns
{
static const FName IdColumnName(TEXT("Id"));
static const FName TimeColumnName(TEXT("Time"));
static const FName VerbosityColumnName(TEXT("Verbosity"));
static const FName CategoryColumnName(TEXT("Category"));
static const FName MessageColumnName(TEXT("Message"));
static const FName FileColumnName(TEXT("File"));
static const FName LineColumnName(TEXT("Line"));
}
////////////////////////////////////////////////////////////////////////////////////////////////////
/**
* Trace log window.
*/
class SLogView : public SCompoundWidget
{
public:
/** Default constructor. */
SLogView();
/** Virtual destructor. */
virtual ~SLogView();
void Reset();
SLATE_BEGIN_ARGS(SLogView) {}
SLATE_END_ARGS()
/**
* Construct this widget.
* @param InArgs - The declaration data for this widget
*/
void Construct(const FArguments& InArgs);
/**
* Ticks this widget. Override in derived classes, but always call the parent implementation.
*
* @param AllottedGeometry - The space allotted for this widget
* @param InCurrentTime - Current absolute real time
* @param InDeltaTime - Real time passed since last tick
*/
virtual void Tick(const FGeometry& AllottedGeometry, const double InCurrentTime, const float InDeltaTime) override;
virtual FReply OnKeyDown(const FGeometry& MyGeometry, const FKeyEvent& InKeyEvent) override;
FLogMessageCache& GetCache() { return Cache; }
TSharedPtr<FLogMessage> GetSelectedLogMessage() const;
void SelectLogMessage(TSharedPtr<FLogMessage> LogMessage);
void SelectLogMessageByLogIndex(int32 LogIndex);
void SelectLogMessageByClosestTime(double Time);
FText GetFilterText() const { return FilterTextBox->GetText(); }
bool IsFilteringAsyncTaskCancelRequested() const { return bIsFilteringAsyncTaskCancelRequested; }
TSharedPtr<TimingProfiler::STimingView> GetTimingView() const;
protected:
/** Generate a new list view row. */
TSharedRef<ITableRow> OnGenerateRow(TSharedPtr<FLogMessage> InLogMessage, const TSharedRef<STableViewBase>& OwnerTable);
void InitCommandList();
void OnMouseButtonClick(TSharedPtr<FLogMessage> LogMessage);
void OnSelectionChanged(TSharedPtr<FLogMessage> LogMessage, ESelectInfo::Type SelectInfo);
void OnSelectedLogMessageChanged(TSharedPtr<FLogMessage> LogMessage);
void FilterTextBox_OnTextChanged(const FText& InFilterText);
void OnFilterChanged();
void UpdateStatsText();
FText GetStatsText() const;
FSlateColor GetStatsTextColor() const;
TSharedPtr<SWidget> ListView_GetContextMenu();
TSharedRef<SWidget> MakeVerbosityThresholdMenu();
void CreateVerbosityThresholdMenuSection(FMenuBuilder& MenuBuilder);
TSharedRef<SWidget> MakeCategoryFilterMenu();
void CreateCategoriesFilterMenuSection(FMenuBuilder& MenuBuilder);
bool VerbosityThreshold_IsChecked(ELogVerbosity::Type Verbosity) const;
void VerbosityThreshold_Execute(ELogVerbosity::Type Verbosity);
const FSlateBrush* VerbosityThreshold_GetSuffixGlyph(ELogVerbosity::Type Verbosity) const;
FSlateColor VerbosityThreshold_GetSuffixColor(ELogVerbosity::Type Verbosity) const;
bool ShowHideAllCategories_IsChecked() const;
void ShowHideAllCategories_Execute();
bool IsLogCategoryEnabled(FName InName) const;
void ToggleCategory(FName InName);
bool CanHideSelectedCategory() const;
void HideSelectedCategory();
bool CanShowOnlySelectedCategory() const;
void ShowOnlySelectedCategory();
bool CanShowAllCategories() const;
void ShowAllCategories();
void AppendFormatMessageDetailed(const FLogMessageRecord& Log, TStringBuilderBase<TCHAR>& InOutStringBuilder) const;
void AppendFormatMessageDelimitedHeader(TStringBuilderBase<TCHAR>& InOutStringBuilder, TCHAR Separator = TEXT('\t')) const;
void AppendFormatMessageDelimited(const FLogMessageRecord& Log, TStringBuilderBase<TCHAR>& InOutStringBuilder, TCHAR Separator = TEXT('\t')) const;
bool CanCopySelected() const;
void CopySelected() const;
bool CanCopyMessage() const;
void CopyMessage() const;
bool CanCopyRange() const;
void CopyRange() const;
bool CanCopyAll() const;
void CopyAll() const;
bool CanSaveRange() const;
void SaveRange() const;
bool CanSaveAll() const;
void SaveAll() const;
void SaveLogsToFile(bool bSaveLogsInSelectedRangeOnly) const;
bool CanOpenSource() const;
void OpenSource() const;
protected:
TSharedPtr<FUICommandList> CommandList;
/** The list view widget. */
TSharedPtr<SListView<TSharedPtr<FLogMessage>>> ListView;
/** External scrollbar used to synchronize tree view position. */
TSharedPtr<SScrollBar> ExternalScrollbar;
/** The search box widget used to filter logs by message text. */
TSharedPtr<SSearchBox> FilterTextBox;
FLogFilter Filter;
uint64 FilterChangeNumber;
int32 FilteringStartIndex; // Start index (of the range of log messages to filter) currently used by the async task
int32 FilteringEndIndex; // End index (of the range of log messages to filter) currently used by the async task
uint64 FilteringChangeNumber; // Change number of the filter currently used by the async task
TUniquePtr<FAsyncTask<FLogFilteringAsyncTask>> FilteringAsyncTask; // The async task to filter log messages on a worker thread
mutable volatile bool bIsFilteringAsyncTaskCancelRequested; // true if we want the async task to finish asap
/** Stopwatch used to measure how long it takes to filter the message list. */
mutable FStopwatch FilteringStopwatch;
/**
* Total number of log categories (including duplicates; last value read from LogProvider).
* Used to detect when more log categories are added in the LogProvider, so we can update UI.
*/
int32 TotalNumCategories;
/**
* Total number of log messages (last value read from LogProvider).
* Used to detect when new log messages are added in the LogProvider, so we can update UI.
*/
int32 TotalNumMessages;
/**
* Total number of inserts in the source table of log messages (last value read from LogProvider).
* Used to detect when the order of log messages changes in source table, so we can invalidate the cache.
*/
int32 TotalNumInserts;
/** true if the list of messages is not yet updated (the filter has changed and/or the source trace messages have changed) */
bool bIsDirty;
/** Stopwatch used to measure the time since the list of messages has become dirty. */
mutable FStopwatch DirtyStopwatch;
/** Stats */
FText StatsText;
/** Cached log messages. */
mutable FLogMessageCache Cache;
/** List of trace log messages to show in list view. */
TArray<TSharedPtr<FLogMessage>> FilteredMessages;
};
////////////////////////////////////////////////////////////////////////////////////////////////////
} // namespace UE::Insights