You've already forked UnrealEngineUWP
mirror of
https://github.com/izzy2lost/UnrealEngineUWP.git
synced 2026-03-26 18:15:20 -07:00
UETOOL-213 - Minimize Slate FString -> FText conversion (remove SLATE_TEXT_ATTRIBUTE) This fixes any editor/engine specific code that was passing text to Slate as FString rather than FText. [CL 2401019 by Jamie Dale in Main branch]
620 lines
16 KiB
C++
620 lines
16 KiB
C++
// Copyright 1998-2015 Epic Games, Inc. All Rights Reserved.
|
|
|
|
#pragma once
|
|
|
|
|
|
#define LOCTEXT_NAMESPACE "SProjectLauncherProgress"
|
|
|
|
|
|
/**
|
|
* Implements the launcher's progress page.
|
|
*/
|
|
class SProjectLauncherProgress
|
|
: public SCompoundWidget
|
|
{
|
|
public:
|
|
|
|
SLATE_BEGIN_ARGS(SProjectLauncherProgress) { }
|
|
SLATE_EVENT(FOnClicked, OnCloseClicked)
|
|
SLATE_EVENT(FOnClicked, OnRerunClicked)
|
|
SLATE_END_ARGS()
|
|
|
|
public:
|
|
|
|
/**
|
|
* Destructor.
|
|
*/
|
|
~SProjectLauncherProgress( )
|
|
{
|
|
|
|
}
|
|
|
|
public:
|
|
|
|
/**
|
|
* Constructs the widget.
|
|
*
|
|
* @param InArgs The Slate argument list.
|
|
*/
|
|
void Construct( const FArguments& InArgs )
|
|
{
|
|
OnCloseClicked = InArgs._OnCloseClicked;
|
|
OnRerunClicked = InArgs._OnRerunClicked;
|
|
|
|
ChildSlot
|
|
[
|
|
SNew(SVerticalBox)
|
|
|
|
+ SVerticalBox::Slot()
|
|
.AutoHeight()
|
|
.Padding(8.0, 16.0, 16.0, 0.0)
|
|
[
|
|
SNew(SVerticalBox)
|
|
|
|
+ SVerticalBox::Slot()
|
|
.AutoHeight()
|
|
[
|
|
SNew(STextBlock)
|
|
.Text(this, &SProjectLauncherProgress::HandleProgressTextBlockText)
|
|
]
|
|
|
|
+ SVerticalBox::Slot()
|
|
.AutoHeight()
|
|
.Padding(0.0, 4.0, 0.0, 0.0)
|
|
[
|
|
SAssignNew(ProgressBar, SProgressBar)
|
|
.Percent(this, &SProjectLauncherProgress::HandleProgressBarPercent)
|
|
]
|
|
]
|
|
|
|
+ SVerticalBox::Slot()
|
|
.FillHeight(0.5)
|
|
.Padding(0.0, 32.0, 8.0, 0.0)
|
|
[
|
|
SNew(SBorder)
|
|
.BorderImage(FEditorStyle::GetBrush("ToolPanel.GroupBorder"))
|
|
.Padding(0.0f)
|
|
[
|
|
SAssignNew(TaskListView, SListView<ILauncherTaskPtr>)
|
|
.HeaderRow
|
|
(
|
|
SNew(SHeaderRow)
|
|
|
|
+ SHeaderRow::Column("Icon")
|
|
.DefaultLabel(LOCTEXT("TaskListIconColumnHeader", " "))
|
|
.FixedWidth(20.0)
|
|
|
|
+ SHeaderRow::Column("Task")
|
|
.DefaultLabel(LOCTEXT("TaskListTaskColumnHeader", "Task"))
|
|
.FillWidth(1.0)
|
|
|
|
+ SHeaderRow::Column("Duration")
|
|
.DefaultLabel(LOCTEXT("TaskListDurationColumnHeader", "Duration"))
|
|
.FixedWidth(64.0)
|
|
|
|
+ SHeaderRow::Column("Status")
|
|
.DefaultLabel(LOCTEXT("TaskListStatusColumnHeader", "Status"))
|
|
.FixedWidth(80.0)
|
|
)
|
|
.ListItemsSource(&TaskList)
|
|
.OnGenerateRow(this, &SProjectLauncherProgress::HandleTaskListViewGenerateRow)
|
|
.ItemHeight(24.0)
|
|
.SelectionMode(ESelectionMode::Single)
|
|
]
|
|
]
|
|
|
|
//content area for the log
|
|
+ SVerticalBox::Slot()
|
|
.FillHeight(0.5)
|
|
.Padding(0.0, 32.0, 8.0, 0.0)
|
|
[
|
|
SNew(SBorder)
|
|
.BorderImage(FEditorStyle::GetBrush("ToolPanel.GroupBorder"))
|
|
.Padding(0.0f)
|
|
[
|
|
SAssignNew(MessageListView, SListView< TSharedPtr<FProjectLauncherMessage> >)
|
|
.HeaderRow
|
|
(
|
|
SNew(SHeaderRow)
|
|
+ SHeaderRow::Column("Status")
|
|
.DefaultLabel(LOCTEXT("TaskListStatusColumnHeader", "Status"))
|
|
.FillWidth(1.0)
|
|
)
|
|
.ListItemsSource(&MessageList)
|
|
.OnGenerateRow(this, &SProjectLauncherProgress::HandleMessageListViewGenerateRow)
|
|
.ItemHeight(24.0)
|
|
.SelectionMode(ESelectionMode::Multi)
|
|
]
|
|
]
|
|
|
|
+ SVerticalBox::Slot()
|
|
.AutoHeight()
|
|
.Padding(0.0f, 5.0f, 0.0f, 0.0f)
|
|
[
|
|
SNew(SHorizontalBox)
|
|
|
|
+ SHorizontalBox::Slot()
|
|
.AutoWidth()
|
|
[
|
|
// copy button
|
|
SAssignNew(CopyButton, SButton)
|
|
.ContentPadding(FMargin(6.0f, 2.0f))
|
|
.IsEnabled(false)
|
|
.Text(LOCTEXT("CopyButtonText", "Copy"))
|
|
.ToolTipText(LOCTEXT("CopyButtonTooltip", "Copy the selected log messages to the clipboard"))
|
|
.OnClicked(this, &SProjectLauncherProgress::HandleCopyButtonClicked)
|
|
]
|
|
|
|
+ SHorizontalBox::Slot()
|
|
.AutoWidth()
|
|
.Padding(4.0f, 0.0f, 0.0f, 0.0f)
|
|
[
|
|
// clear button
|
|
SAssignNew(ClearButton, SButton)
|
|
.ContentPadding(FMargin(6.0f, 2.0f))
|
|
.IsEnabled(false)
|
|
.Text(LOCTEXT("ClearButtonText", "Clear Log"))
|
|
.ToolTipText(LOCTEXT("ClearButtonTooltip", "Clear the log window"))
|
|
.OnClicked(this, &SProjectLauncherProgress::HandleClearButtonClicked)
|
|
]
|
|
|
|
+ SHorizontalBox::Slot()
|
|
.AutoWidth()
|
|
.Padding(4.0f, 0.0f, 0.0f, 0.0f)
|
|
[
|
|
// save button
|
|
SAssignNew(SaveButton, SButton)
|
|
.ContentPadding(FMargin(6.0f, 2.0f))
|
|
.IsEnabled(false)
|
|
.Text(LOCTEXT("ExportButtonText", "Save Log..."))
|
|
.ToolTipText(LOCTEXT("SaveButtonTooltip", "Save the entire log to a file"))
|
|
.Visibility((FDesktopPlatformModule::Get() != NULL) ? EVisibility::Visible : EVisibility::Collapsed)
|
|
.OnClicked(this, &SProjectLauncherProgress::HandleSaveButtonClicked)
|
|
]
|
|
|
|
+ SHorizontalBox::Slot()
|
|
.AutoWidth()
|
|
.Padding(4.0f, 0.0f, 0.0f, 0.0f)
|
|
[
|
|
// Re-Run button
|
|
SNew(SButton)
|
|
.ContentPadding(FMargin(6.0f, 2.0f))
|
|
.IsEnabled(this, &SProjectLauncherProgress::IsRerunButtonEnabled)
|
|
.OnClicked(this, &SProjectLauncherProgress::HandleRerunButtonClicked)
|
|
.ToolTipText(this, &SProjectLauncherProgress::GetRerunButtonToolTip)
|
|
[
|
|
SNew(STextBlock)
|
|
.Text(this, &SProjectLauncherProgress::GetRerunButtonText)
|
|
]
|
|
]
|
|
|
|
+ SHorizontalBox::Slot()
|
|
.AutoWidth()
|
|
.Padding(4.0f, 0.0f, 0.0f, 0.0f)
|
|
[
|
|
// Cancel / Done button
|
|
SNew(SButton)
|
|
.ContentPadding(FMargin(6.0f, 2.0f))
|
|
.IsEnabled(this, &SProjectLauncherProgress::IsDoneButtonEnabled)
|
|
.OnClicked(this, &SProjectLauncherProgress::HandleDoneButtonClicked)
|
|
.ToolTipText(this, &SProjectLauncherProgress::GetDoneButtonToolTip)
|
|
[
|
|
SNew(STextBlock)
|
|
.Text(this, &SProjectLauncherProgress::GetDoneButtonText)
|
|
]
|
|
]
|
|
]
|
|
];
|
|
}
|
|
|
|
/**
|
|
* Sets the launcher worker to track the progress for.
|
|
*
|
|
* @param Worker The launcher worker.
|
|
*/
|
|
void SetLauncherWorker( const ILauncherWorkerRef& Worker )
|
|
{
|
|
LauncherWorker = Worker;
|
|
|
|
Worker->GetTasks(TaskList);
|
|
TaskListView->RequestListRefresh();
|
|
|
|
MessageList.Reset();
|
|
Worker->OnOutputReceived().AddRaw(this, &SProjectLauncherProgress::HandleOutputReceived);
|
|
MessageListView->RequestListRefresh();
|
|
}
|
|
|
|
void Tick( const FGeometry& AllottedGeometry, const double InCurrentTime, const float InDeltaTime ) override
|
|
{
|
|
if (PendingMessages.Num() > 0)
|
|
{
|
|
FScopeLock ScopedLock(&CriticalSection);
|
|
for (int32 Index = 0; Index < PendingMessages.Num(); ++Index)
|
|
{
|
|
MessageList.Add(PendingMessages[Index]);
|
|
}
|
|
PendingMessages.Reset();
|
|
MessageListView->RequestListRefresh();
|
|
MessageListView->RequestScrollIntoView(MessageList.Last());
|
|
}
|
|
SaveButton->SetEnabled(MessageList.Num() > 0);
|
|
ClearButton->SetEnabled(MessageList.Num() > 0);
|
|
CopyButton->SetEnabled(MessageListView->GetNumItemsSelected() > 0);
|
|
}
|
|
|
|
private:
|
|
|
|
void HandleOutputReceived(const FString& InMessage)
|
|
{
|
|
FScopeLock ScopedLock(&CriticalSection);
|
|
ELogVerbosity::Type Verbosity = ELogVerbosity::Log;
|
|
|
|
if (InMessage.Contains(TEXT("Automation.ParseCommandLine:"), ESearchCase::CaseSensitive))
|
|
{
|
|
Verbosity = ELogVerbosity::Display;
|
|
}
|
|
else if ( InMessage.Contains(TEXT("Error:"), ESearchCase::IgnoreCase) )
|
|
{
|
|
Verbosity = ELogVerbosity::Error;
|
|
}
|
|
else if ( InMessage.Contains(TEXT("Warning:"), ESearchCase::IgnoreCase) )
|
|
{
|
|
Verbosity = ELogVerbosity::Warning;
|
|
}
|
|
TSharedPtr<FProjectLauncherMessage> Message = MakeShareable(new FProjectLauncherMessage(FText::FromString(InMessage), Verbosity));
|
|
PendingMessages.Add(Message);
|
|
}
|
|
|
|
// Callback for getting the filled percentage of the progress bar.
|
|
TOptional<float> HandleProgressBarPercent( ) const
|
|
{
|
|
if (TaskList.Num() > 0)
|
|
{
|
|
ILauncherWorkerPtr LauncherWorkerPtr = LauncherWorker.Pin();
|
|
|
|
if (LauncherWorkerPtr.IsValid())
|
|
{
|
|
int32 NumFinished = 0;
|
|
|
|
for (int32 TaskIndex = 0; TaskIndex < TaskList.Num(); ++TaskIndex)
|
|
{
|
|
if (TaskList[TaskIndex]->IsFinished())
|
|
{
|
|
++NumFinished;
|
|
}
|
|
}
|
|
|
|
return ((float)NumFinished / TaskList.Num());
|
|
}
|
|
}
|
|
|
|
return 0.0f;
|
|
}
|
|
|
|
// Callback for getting the text of the progress text box.
|
|
FText HandleProgressTextBlockText( ) const
|
|
{
|
|
ILauncherWorkerPtr LauncherWorkerPtr = LauncherWorker.Pin();
|
|
|
|
if (LauncherWorkerPtr.IsValid())
|
|
{
|
|
if ((LauncherWorkerPtr->GetStatus() == ELauncherWorkerStatus::Busy) ||
|
|
(LauncherWorkerPtr->GetStatus() == ELauncherWorkerStatus::Canceling))
|
|
{
|
|
return LOCTEXT("OperationInProgressText", "Operation in progress...");
|
|
}
|
|
|
|
int32 NumCanceled = 0;
|
|
int32 NumCompleted = 0;
|
|
int32 NumFailed = 0;
|
|
|
|
for (int32 TaskIndex = 0; TaskIndex < TaskList.Num(); ++TaskIndex)
|
|
{
|
|
ELauncherTaskStatus::Type TaskStatus = TaskList[TaskIndex]->GetStatus();
|
|
|
|
if (TaskStatus == ELauncherTaskStatus::Canceled)
|
|
{
|
|
++NumCanceled;
|
|
}
|
|
else if (TaskStatus == ELauncherTaskStatus::Completed)
|
|
{
|
|
++NumCompleted;
|
|
}
|
|
else if (TaskStatus == ELauncherTaskStatus::Failed)
|
|
{
|
|
++NumFailed;
|
|
}
|
|
}
|
|
|
|
FFormatNamedArguments Args;
|
|
Args.Add(TEXT("NumCompleted"), NumCompleted);
|
|
Args.Add(TEXT("NumFailed"), NumFailed);
|
|
Args.Add(TEXT("NumCanceled"), NumCanceled);
|
|
|
|
return FText::Format(LOCTEXT("TasksFinishedFormatText", "Operation finished. Completed: {NumCompleted}, Failed: {NumFailed}, Canceled: {NumCanceled}"), Args);
|
|
}
|
|
|
|
return FText::GetEmpty();
|
|
}
|
|
|
|
// Callback for generating a row in the task list view.
|
|
TSharedRef<ITableRow> HandleTaskListViewGenerateRow( ILauncherTaskPtr InItem, const TSharedRef<STableViewBase>& OwnerTable ) const
|
|
{
|
|
return SNew(SProjectLauncherTaskListRow)
|
|
.Task(InItem)
|
|
.OwnerTableView(OwnerTable);
|
|
}
|
|
|
|
// Callback for generating a row in the task list view.
|
|
TSharedRef<ITableRow> HandleMessageListViewGenerateRow( TSharedPtr<FProjectLauncherMessage> InItem, const TSharedRef<STableViewBase>& OwnerTable ) const
|
|
{
|
|
return SNew(SProjectLauncherMessageListRow, OwnerTable)
|
|
.Message(InItem)
|
|
.ToolTipText(InItem->Message);
|
|
}
|
|
|
|
FReply HandleClearButtonClicked( )
|
|
{
|
|
ClearLog();
|
|
return FReply::Handled();
|
|
}
|
|
|
|
FReply HandleCopyButtonClicked( )
|
|
{
|
|
CopyLog();
|
|
return FReply::Handled();
|
|
}
|
|
|
|
FReply HandleSaveButtonClicked( )
|
|
{
|
|
SaveLog();
|
|
return FReply::Handled();
|
|
}
|
|
|
|
bool IsRerunButtonEnabled() const
|
|
{
|
|
ILauncherWorkerPtr LauncherWorkerPtr = LauncherWorker.Pin();
|
|
|
|
if (LauncherWorkerPtr.IsValid() &&
|
|
(LauncherWorkerPtr->GetStatus() == ELauncherWorkerStatus::Canceled || LauncherWorkerPtr->GetStatus() == ELauncherWorkerStatus::Completed))
|
|
{
|
|
return true;
|
|
}
|
|
|
|
return false;
|
|
}
|
|
|
|
FReply HandleRerunButtonClicked()
|
|
{
|
|
if (OnRerunClicked.IsBound())
|
|
{
|
|
return OnRerunClicked.Execute();
|
|
}
|
|
|
|
return FReply::Handled();
|
|
}
|
|
|
|
FText GetRerunButtonToolTip() const
|
|
{
|
|
return LOCTEXT("DoneButtonCloseTooltip", "Run this launch profile.");
|
|
}
|
|
|
|
FText GetRerunButtonText() const
|
|
{
|
|
return LOCTEXT("DoneButtonDoneLabel", "Run");
|
|
}
|
|
|
|
bool IsDoneButtonEnabled() const
|
|
{
|
|
ILauncherWorkerPtr LauncherWorkerPtr = LauncherWorker.Pin();
|
|
|
|
if (LauncherWorkerPtr.IsValid() && LauncherWorkerPtr->GetStatus() == ELauncherWorkerStatus::Canceling)
|
|
{
|
|
return false;
|
|
}
|
|
|
|
return true;
|
|
}
|
|
|
|
FReply HandleDoneButtonClicked()
|
|
{
|
|
ILauncherWorkerPtr LauncherWorkerPtr = LauncherWorker.Pin();
|
|
|
|
if (LauncherWorkerPtr.IsValid() && LauncherWorkerPtr->GetStatus() == ELauncherWorkerStatus::Busy)
|
|
{
|
|
LauncherWorkerPtr->Cancel();
|
|
}
|
|
else if (LauncherWorkerPtr.IsValid() && LauncherWorkerPtr->GetStatus() == ELauncherWorkerStatus::Canceling)
|
|
{
|
|
// do nothing
|
|
}
|
|
else if (OnCloseClicked.IsBound())
|
|
{
|
|
return OnCloseClicked.Execute();
|
|
}
|
|
|
|
return FReply::Handled();
|
|
}
|
|
|
|
FText GetDoneButtonToolTip() const
|
|
{
|
|
ILauncherWorkerPtr LauncherWorkerPtr = LauncherWorker.Pin();
|
|
|
|
if (LauncherWorkerPtr.IsValid())
|
|
{
|
|
if (LauncherWorkerPtr->GetStatus() == ELauncherWorkerStatus::Busy)
|
|
{
|
|
return LOCTEXT("DoneButtonCancelTooltip", "Cancel the run of this profile.");
|
|
}
|
|
else if (LauncherWorkerPtr->GetStatus() == ELauncherWorkerStatus::Canceling)
|
|
{
|
|
return LOCTEXT("DoneButtonCancellingTooltip", "Currently canceling.");
|
|
}
|
|
}
|
|
return LOCTEXT("DoneButtonCloseTooltip", "Close this page.");
|
|
}
|
|
FText GetDoneButtonText() const
|
|
{
|
|
ILauncherWorkerPtr LauncherWorkerPtr = LauncherWorker.Pin();
|
|
|
|
if (LauncherWorkerPtr.IsValid())
|
|
{
|
|
if (LauncherWorkerPtr->GetStatus() == ELauncherWorkerStatus::Busy)
|
|
{
|
|
return LOCTEXT("DoneButtonCancelLabel", "Cancel");
|
|
}
|
|
else if (LauncherWorkerPtr->GetStatus() == ELauncherWorkerStatus::Canceling)
|
|
{
|
|
return LOCTEXT("DoneButtonCancellingLabel", "Cancelling");
|
|
}
|
|
}
|
|
return LOCTEXT("DoneButtonDoneLabel", "Done");
|
|
}
|
|
|
|
|
|
void ClearLog()
|
|
{
|
|
MessageList.Reset();
|
|
MessageListView->RequestListRefresh();
|
|
}
|
|
|
|
void CopyLog()
|
|
{
|
|
TArray<TSharedPtr<FProjectLauncherMessage > > SelectedItems = MessageListView->GetSelectedItems();
|
|
|
|
if (SelectedItems.Num() > 0)
|
|
{
|
|
FString SelectedText;
|
|
|
|
for( int32 Index = 0; Index < SelectedItems.Num(); ++Index )
|
|
{
|
|
SelectedText += SelectedItems[Index]->Message.ToString();
|
|
SelectedText += LINE_TERMINATOR;
|
|
}
|
|
|
|
FPlatformMisc::ClipboardCopy( *SelectedText );
|
|
}
|
|
}
|
|
|
|
void SaveLog()
|
|
{
|
|
IDesktopPlatform* DesktopPlatform = FDesktopPlatformModule::Get();
|
|
|
|
if (DesktopPlatform != NULL)
|
|
{
|
|
TArray<FString> Filenames;
|
|
|
|
TSharedPtr<SWindow> ParentWindow = FSlateApplication::Get().FindWidgetWindow(AsShared());
|
|
void* ParentWindowHandle = (ParentWindow.IsValid() && ParentWindow->GetNativeWindow().IsValid()) ? ParentWindow->GetNativeWindow()->GetOSWindowHandle() : nullptr;
|
|
|
|
if (DesktopPlatform->SaveFileDialog(
|
|
ParentWindowHandle,
|
|
LOCTEXT("SaveLogDialogTitle", "Save Log As...").ToString(),
|
|
LastLogFileSaveDirectory,
|
|
TEXT("ProjectLauncher.log"),
|
|
TEXT("Log Files (*.log)|*.log"),
|
|
EFileDialogFlags::None,
|
|
Filenames))
|
|
{
|
|
if (Filenames.Num() > 0)
|
|
{
|
|
FString Filename = Filenames[0];
|
|
|
|
// keep path as default for next time
|
|
LastLogFileSaveDirectory = FPaths::GetPath(Filename);
|
|
|
|
// add a file extension if none was provided
|
|
if (FPaths::GetExtension(Filename).IsEmpty())
|
|
{
|
|
Filename += Filename + TEXT(".log");
|
|
}
|
|
|
|
// save file
|
|
FArchive* LogFile = IFileManager::Get().CreateFileWriter(*Filename);
|
|
|
|
if (LogFile != NULL)
|
|
{
|
|
for( int32 Index = 0; Index < MessageList.Num(); ++Index )
|
|
{
|
|
FString LogEntry = MessageList[Index]->Message.ToString() + LINE_TERMINATOR;
|
|
|
|
LogFile->Serialize(TCHAR_TO_ANSI(*LogEntry), LogEntry.Len());
|
|
}
|
|
|
|
LogFile->Close();
|
|
|
|
delete LogFile;
|
|
}
|
|
else
|
|
{
|
|
FMessageDialog::Open(EAppMsgType::Ok, LOCTEXT("SaveLogDialogFileError", "Failed to open the specified file for saving!"));
|
|
}
|
|
}
|
|
}
|
|
}
|
|
else
|
|
{
|
|
FMessageDialog::Open(EAppMsgType::Ok, LOCTEXT("SaveLogDialogUnsupportedError", "Saving is not supported on this platform!"));
|
|
}
|
|
}
|
|
|
|
private:
|
|
|
|
// Holds the launcher worker.
|
|
TWeakPtr<ILauncherWorker> LauncherWorker;
|
|
|
|
// Holds the output log.
|
|
TArray<TSharedPtr<FString>> OutputList;
|
|
|
|
// Holds the output list view.
|
|
TSharedPtr<SListView<TSharedPtr<FString>>> OutputListView;
|
|
|
|
// Holds the progress bar.
|
|
TSharedPtr<SProgressBar> ProgressBar;
|
|
|
|
// Holds the task list.
|
|
TArray<ILauncherTaskPtr> TaskList;
|
|
|
|
// Holds the message list.
|
|
TArray< TSharedPtr<FProjectLauncherMessage>> MessageList;
|
|
|
|
// Holds the filtered message list.
|
|
TArray< TSharedPtr<FProjectLauncherMessage>> FilterMessageList;
|
|
|
|
// Holds the pending message list.
|
|
TArray< TSharedPtr<FProjectLauncherMessage>> PendingMessages;
|
|
|
|
// Holds the message list view.
|
|
TSharedPtr<SListView<TSharedPtr<FProjectLauncherMessage>>> MessageListView;
|
|
|
|
// Holds the task list view.
|
|
TSharedPtr<SListView<ILauncherTaskPtr>> TaskListView;
|
|
|
|
// Holds the box of task statuses.
|
|
TSharedPtr<SVerticalBox> TaskStatusBox;
|
|
|
|
// Critical section for updating the messages
|
|
FCriticalSection CriticalSection;
|
|
|
|
// Holds the directory where the log file was last saved to.
|
|
FString LastLogFileSaveDirectory;
|
|
|
|
// Holds the copy log button.
|
|
TSharedPtr<SButton> CopyButton;
|
|
|
|
// Holds the clear button.
|
|
TSharedPtr<SButton> ClearButton;
|
|
|
|
// Holds the save button.
|
|
TSharedPtr<SButton> SaveButton;
|
|
|
|
// Holds a delegate to be invoked when this panel is closed.
|
|
FOnClicked OnCloseClicked;
|
|
|
|
// Holds a delegate to be invoked when we want the launch profile rerun.
|
|
FOnClicked OnRerunClicked;
|
|
};
|
|
|
|
|
|
#undef LOCTEXT_NAMESPACE
|