Files
UnrealEngine/Engine/Source/Developer/TraceInsightsFrontend/Private/InsightsFrontend/Widgets/STraceDirectoryItem.cpp
2025-05-18 13:04:45 +08:00

304 lines
9.4 KiB
C++

// Copyright Epic Games, Inc. All Rights Reserved.
#include "STraceDirectoryItem.h"
#include "DesktopPlatformModule.h"
#include "Framework/Application/SlateApplication.h"
#include "Logging/MessageLog.h"
#include "Misc/PathViews.h"
#include "SlateOptMacros.h"
#include "Widgets/Input/SButton.h"
#include "Widgets/Layout/SBorder.h"
#include "Widgets/Layout/SBox.h"
#include "Widgets/SBoxPanel.h"
// TraceAnalysis
#include "Trace/StoreClient.h"
#include "Trace/StoreConnection.h"
// TraceInsightsCore
#include "InsightsCore/Common/InsightsCoreStyle.h"
#include "InsightsCore/Common/MessageDialogUtils.h"
// TraceInsightsFrontend
#include "InsightsFrontend/Common/InsightsFrontendStyle.h"
#include "InsightsFrontend/Common/Log.h"
#include "InsightsFrontend/Widgets/STraceStoreWindow.h"
#define LOCTEXT_NAMESPACE "UE::Insights::STraceDirectoryItem"
namespace UE::Insights
{
////////////////////////////////////////////////////////////////////////////////////////////////////
BEGIN_SLATE_FUNCTION_BUILD_OPTIMIZATION
void STraceDirectoryItem::Construct(const FArguments& InArgs, TSharedPtr<FTraceDirectoryModel> InModel, STraceStoreWindow* InWindow)
{
Model = InModel;
Window = InWindow;
ChildSlot
[
SNew(SBorder)
.Padding(2.0f, 1.0f)
[
SNew(SHorizontalBox)
+ SHorizontalBox::Slot()
.Padding(4.0f, 2.0f)
.AutoWidth()
.VAlign(EVerticalAlignment::VAlign_Center)
[
SNew(SBox)
.HeightOverride(16.0f)
.WidthOverride(16.0f)
[
SNew(SImage)
.Image(FInsightsFrontendStyle::Get().GetBrush("Icons.UTraceStack"))
.ColorAndOpacity(GetColor())
]
]
+ SHorizontalBox::Slot()
.FillWidth(1.0f)
.Padding(4.0f, 2.0f)
.VAlign(EVerticalAlignment::VAlign_Center)
[
SNew(STextBlock)
.Text(FText::FromString(Model->Path))
]
+ SHorizontalBox::Slot()
.Padding(4.0f, 2.0f)
.AutoWidth()
[
ConstructOperations()
]
]
];
}
END_SLATE_FUNCTION_BUILD_OPTIMIZATION
////////////////////////////////////////////////////////////////////////////////////////////////////
FSlateColor STraceDirectoryItem::GetColor() const
{
if (Model && Model->Color != NAME_None)
{
return FAppStyle::Get().GetSlateColor(Model->Color);
}
return FSlateColor::UseForeground();
}
////////////////////////////////////////////////////////////////////////////////////////////////////
BEGIN_SLATE_FUNCTION_BUILD_OPTIMIZATION
TSharedRef<SWidget> STraceDirectoryItem::ConstructOperations()
{
TSharedRef<SHorizontalBox> Box = SNew(SHorizontalBox);
if (Model && EnumHasAllFlags(Model->Operations, ETraceDirOperations::ModifyStore))
{
Box->AddSlot()
.AutoWidth()
[
SNew(SButton)
.ButtonStyle(&FAppStyle::Get().GetWidgetStyle<FButtonStyle>("SimpleButton"))
.ToolTipText_Raw(this, &STraceDirectoryItem::ModifyStoreTooltip)
.OnClicked_Raw(this, &STraceDirectoryItem::OnModifyStore)
.IsEnabled_Raw(this, &STraceDirectoryItem::CanModifyStore)
[
SNew(SImage)
.Image(FAppStyle::Get().GetBrush("Icons.Edit"))
.ColorAndOpacity(FSlateColor::UseForeground())
]
];
}
if (Model && EnumHasAllFlags(Model->Operations, ETraceDirOperations::Delete))
{
Box->AddSlot()
.AutoWidth()
[
SNew(SButton)
.ButtonStyle(&FAppStyle::Get().GetWidgetStyle<FButtonStyle>("SimpleButton"))
.ToolTipText(LOCTEXT("WatchDirsRemoveTooltip", "Removes the monitored directory. Files will not be deleted."))
.OnClicked_Raw(this, &STraceDirectoryItem::OnDelete)
.IsEnabled_Raw(this, &STraceDirectoryItem::CanDelete)
[
SNew(SImage)
.Image(FInsightsFrontendStyle::Get().GetBrush("Icons.RemoveWatchDir"))
.ColorAndOpacity(FSlateColor::UseForeground())
]
];
}
if (Model && EnumHasAllFlags(Model->Operations, ETraceDirOperations::Explore))
{
// If it has a Delete button then it is a "monitored directory".
bool bIsWatchDir = (Model && EnumHasAllFlags(Model->Operations, ETraceDirOperations::Delete));
Box->AddSlot()
.AutoWidth()
[
SNew(SButton)
.ButtonStyle(&FAppStyle::Get().GetWidgetStyle<FButtonStyle>("SimpleButton"))
.ToolTipText(bIsWatchDir ?
LOCTEXT("ExploreWatchDirButtonToolTip", "Explores the monitored directory.") :
LOCTEXT("ExploreTraceStoreDirButtonToolTip", "Explores the Trace Store Directory."))
.OnClicked_Raw(this, &STraceDirectoryItem::OnExplore)
.IsEnabled_Raw(this, &STraceDirectoryItem::CanExplore)
[
SNew(SImage)
.Image(FInsightsCoreStyle::Get().GetBrush("Icons.FolderExplore"))
.ColorAndOpacity(FSlateColor::UseForeground())
]
];
}
return Box;
}
END_SLATE_FUNCTION_BUILD_OPTIMIZATION
////////////////////////////////////////////////////////////////////////////////////////////////////
bool STraceDirectoryItem::CanExplore() const
{
return Window && Window->GetTraceStoreConnection().CanChangeStoreSettings();
}
////////////////////////////////////////////////////////////////////////////////////////////////////
FReply STraceDirectoryItem::OnExplore()
{
FSlateApplication::Get().CloseToolTip();
if (Model)
{
FString FullPath(FPaths::ConvertRelativePathToFull(Model->Path));
FPlatformProcess::ExploreFolder(*FullPath);
}
return FReply::Handled();
}
////////////////////////////////////////////////////////////////////////////////////////////////////
bool STraceDirectoryItem::CanDelete() const
{
return Window && Window->GetTraceStoreConnection().CanChangeStoreSettings();
}
////////////////////////////////////////////////////////////////////////////////////////////////////
FReply STraceDirectoryItem::OnDelete()
{
FSlateApplication::Get().CloseToolTip();
// Avoid executing more than one operation
if (bInOperation)
{
return FReply::Handled();
}
TGuardValue<bool> OperationGuard(bInOperation, true);
if (Model)
{
EDialogResponse Response = FMessageDialogUtils::ShowChoiceDialog(LOCTEXT("MonitoredDirRemoveConfirmTitle", "Confirm removing monitored directory"), FText::Format(
LOCTEXT("MonitoredDirRemoveConfirmFmt", "This will remove \"{0}\" from monitored directories.\n\nConfirm removing monitored directory?"),
FText::FromString(Model->Path)));
if (Response == EDialogResponse::OK)
{
UE_LOG(LogInsightsFrontend, Log, TEXT("[TraceStore] Removing monitored directory: \"%s\"..."), *Model->Path);
UE::Trace::FStoreClient* StoreClient = Window->GetTraceStoreConnection().GetStoreClient();
if (!StoreClient ||
!StoreClient->SetStoreDirectories(nullptr, {}, { *Model->Path }))
{
FName LogListingName(TEXT("UnrealInsights"));
FMessageLog(LogListingName).Error(LOCTEXT("StoreCommunicationFail", "Failed to change settings on the store service."));
}
}
}
return FReply::Handled();
}
////////////////////////////////////////////////////////////////////////////////////////////////////
bool STraceDirectoryItem::CanModifyStore() const
{
return Window &&
!Window->HasAnyLiveTrace() &&
Window->GetTraceStoreConnection().CanChangeStoreSettings();
}
////////////////////////////////////////////////////////////////////////////////////////////////////
FReply STraceDirectoryItem::OnModifyStore()
{
FSlateApplication::Get().CloseToolTip();
// Avoid executing more than one operation
if (bInOperation)
{
return FReply::Handled();
}
TGuardValue<bool> OperationGuard(bInOperation, true);
if (IDesktopPlatform* DesktopPlatform = FDesktopPlatformModule::Get())
{
const FString Title = LOCTEXT("SetTraceStoreDirectory_DialogTitle", "Set Trace Store Directory").ToString();
FString CurrentStoreDirectory = Window->GetStoreDirectory();
FString SelectedDirectory;
const bool bHasSelected = DesktopPlatform->OpenDirectoryDialog(
FSlateApplication::Get().FindBestParentWindowHandleForDialogs(AsShared()),
Title,
CurrentStoreDirectory,
SelectedDirectory);
const bool bIsWatchDir = Window->WatchDirectoriesModel.FindByPredicate([&](const auto& Directory) { return FPathViews::Equals(SelectedDirectory, Directory->Path); }) != nullptr;
const bool bIsCurrentStoreDir = FPathViews::Equals(SelectedDirectory, CurrentStoreDirectory);
if (bHasSelected && !bIsCurrentStoreDir)
{
FPaths::MakePlatformFilename(SelectedDirectory);
FPaths::MakePlatformFilename(CurrentStoreDirectory);
const TArray<FString> AddWatchDirs = { CurrentStoreDirectory };
TArray<FString> RemoveWatchDirs;
if (bIsWatchDir)
{
// If we are selecting a monitored dir as new store dir, make
// sure we remove it as monitored directory.
RemoveWatchDirs.Emplace(SelectedDirectory);
}
UE_LOG(LogInsightsFrontend, Log, TEXT("[TraceStore] Changing store directory: \"%s\"..."), *SelectedDirectory);
UE::Trace::FStoreClient* StoreClient = Window->GetTraceStoreConnection().GetStoreClient();
if (!StoreClient ||
!StoreClient->SetStoreDirectories(*SelectedDirectory, AddWatchDirs, RemoveWatchDirs))
{
FName LogListingName(TEXT("UnrealInsights"));
FMessageLog(LogListingName).Error(LOCTEXT("StoreCommunicationFail", "Failed to change settings on the store service."));
}
}
}
return FReply::Handled();
}
////////////////////////////////////////////////////////////////////////////////////////////////////
FText STraceDirectoryItem::ModifyStoreTooltip() const
{
return CanModifyStore() ?
LOCTEXT("SetTraceStoreDirButtonToolTip", "Sets the Trace Store Directory.") :
LOCTEXT("SetTraceStoreDirButtonTooltipInactive", "Sets the Trace Store Directory.\nNot available while live trace sessions are running.");
}
////////////////////////////////////////////////////////////////////////////////////////////////////
} // namespace UE::Insights
#undef LOCTEXT_NAMESPACE