You've already forked UnrealEngineUWP
mirror of
https://github.com/izzy2lost/UnrealEngineUWP.git
synced 2026-03-26 18:15:20 -07:00
* Rename blacklist to excludelist (requested by high management) * Support section exclusion rule to be able to exclude entire section of tests (ie PathTracing is only supported on Win64 for now) * Mark excluded test as skipped in the report instead of entirely removed for test list. Check for exclusion just before running the test. * Remove NotEnoughParticipant state in favor of Skipped (same conditions lead to Skipped state with appropriate messaging) * Add support for exclusion management from the Test Automation window. (added a column at the end of each row) * Expose device information to UE test report * Add support for metadata in Gauntlet test report for Horde Limitations: * Management through the UI is limited to which test is available through in the active worker node. That's mean Runtime only tests are not listed from a worker that is Editor(the default) and platform specific are not clearly identified. * For platforms, the mechanic to access their config and save it will remain to be done. In the meantime, it needs to be done manually through the target platform config file. #jira UE-125960 #jira UE-125974 #ROBOMERGE-AUTHOR: jerome.delattre #ROBOMERGE-SOURCE: CL 17607554 in //UE5/Main/... #ROBOMERGE-BOT: STARSHIP (Main -> Release-Engine-Test) (v871-17566257) [CL 17607557 by jerome delattre in ue5-release-engine-test branch]
2301 lines
68 KiB
C++
2301 lines
68 KiB
C++
// Copyright Epic Games, Inc. All Rights Reserved.
|
|
|
|
#include "SAutomationWindow.h"
|
|
#include "HAL/PlatformProcess.h"
|
|
#include "HAL/PlatformApplicationMisc.h"
|
|
#include "PlatformInfo.h"
|
|
#include "Misc/MessageDialog.h"
|
|
#include "Misc/TextFilter.h"
|
|
#include "Misc/FilterCollection.h"
|
|
#include "Widgets/Layout/SSplitter.h"
|
|
#include "SlateOptMacros.h"
|
|
#include "Textures/SlateIcon.h"
|
|
#include "Framework/Commands/InputChord.h"
|
|
#include "Framework/Commands/UIAction.h"
|
|
#include "Framework/Commands/Commands.h"
|
|
#include "Framework/Commands/UICommandList.h"
|
|
#include "Widgets/Images/SImage.h"
|
|
#include "Framework/MultiBox/MultiBoxDefs.h"
|
|
#include "Framework/MultiBox/MultiBoxBuilder.h"
|
|
#include "Widgets/Input/SEditableTextBox.h"
|
|
#include "Widgets/Input/SButton.h"
|
|
#include "Widgets/Layout/SScrollBox.h"
|
|
#include "Widgets/Input/SCheckBox.h"
|
|
#include "Widgets/Input/SSpinBox.h"
|
|
#include "EditorStyleSet.h"
|
|
#include "SAutomationWindowCommandBar.h"
|
|
#include "AutomationFilter.h"
|
|
#include "AutomationPresetManager.h"
|
|
#include "SAutomationTestItemContextMenu.h"
|
|
#include "SAutomationTestItem.h"
|
|
|
|
#if WITH_EDITOR
|
|
#include "Engine/World.h"
|
|
#include "FileHelpers.h"
|
|
#include "AssetRegistryModule.h"
|
|
#endif
|
|
|
|
#include "Widgets/Input/SSearchBox.h"
|
|
#include "Widgets/Notifications/SNotificationList.h"
|
|
#include "Widgets/Images/SThrobber.h"
|
|
#include "Widgets/Input/SHyperlink.h"
|
|
#include "Internationalization/Regex.h"
|
|
|
|
|
|
#define LOCTEXT_NAMESPACE "AutomationTest"
|
|
|
|
|
|
//////////////////////////////////////////////////////////////////////////
|
|
// FAutomationWindowCommands
|
|
|
|
class FAutomationWindowCommands : public TCommands<FAutomationWindowCommands>
|
|
{
|
|
public:
|
|
FAutomationWindowCommands()
|
|
: TCommands<FAutomationWindowCommands>(
|
|
TEXT("AutomationWindow"),
|
|
NSLOCTEXT("Contexts", "AutomationWindow", "Automation Window"),
|
|
NAME_None, FEditorStyle::GetStyleSetName()
|
|
)
|
|
{
|
|
}
|
|
|
|
virtual void RegisterCommands() override
|
|
{
|
|
UI_COMMAND( RefreshTests, "Refresh Tests", "Refresh Tests", EUserInterfaceActionType::Button, FInputChord() );
|
|
UI_COMMAND( FindWorkers, "Find Workers", "Find Workers", EUserInterfaceActionType::Button, FInputChord() );
|
|
UI_COMMAND( ErrorFilter, "Errors", "Toggle Error Filter", EUserInterfaceActionType::ToggleButton, FInputChord() );
|
|
UI_COMMAND( WarningFilter, "Warnings", "Toggle Warning Filter", EUserInterfaceActionType::ToggleButton, FInputChord() );
|
|
UI_COMMAND( DeveloperDirectoryContent, "Dev Content", "Developer Directory Content Filter (when enabled, developer directories are also included)", EUserInterfaceActionType::ToggleButton, FInputChord() );
|
|
UI_COMMAND( ExcludedTestsFilter, "Excluded Tests", "Toggle Excluded Tests only", EUserInterfaceActionType::ToggleButton, FInputChord());
|
|
|
|
#if WITH_EDITOR
|
|
// Added button for running the currently open level test.
|
|
UI_COMMAND(RunLevelTest, "Run Level Test", "Run Level Test", EUserInterfaceActionType::Button, FInputChord());
|
|
#endif
|
|
}
|
|
public:
|
|
TSharedPtr<FUICommandInfo> RefreshTests;
|
|
TSharedPtr<FUICommandInfo> FindWorkers;
|
|
TSharedPtr<FUICommandInfo> ErrorFilter;
|
|
TSharedPtr<FUICommandInfo> WarningFilter;
|
|
TSharedPtr<FUICommandInfo> DeveloperDirectoryContent;
|
|
TSharedPtr<FUICommandInfo> ExcludedTestsFilter;
|
|
|
|
#if WITH_EDITOR
|
|
TSharedPtr<FUICommandInfo> RunLevelTest;
|
|
#endif
|
|
};
|
|
|
|
//////////////////////////////////////////////////////////////////////////
|
|
// SAutomationWindow
|
|
|
|
SAutomationWindow::SAutomationWindow()
|
|
: ColumnWidth(50.0f)
|
|
{
|
|
|
|
}
|
|
|
|
SAutomationWindow::~SAutomationWindow()
|
|
{
|
|
// @todo PeterMcW: is there an actual delegate missing here?
|
|
//give the controller a way to indicate it requires a UI update
|
|
//AutomationController->SetRefreshTestCallback(FOnAutomationControllerTestsRefreshed());
|
|
|
|
// Remove ourselves from the session manager
|
|
if( SessionManager.IsValid( ) )
|
|
{
|
|
SessionManager->OnCanSelectSession().RemoveAll(this);
|
|
SessionManager->OnSelectedSessionChanged().RemoveAll(this);
|
|
SessionManager->OnSessionInstanceUpdated().RemoveAll(this);
|
|
}
|
|
|
|
if (AutomationController.IsValid())
|
|
{
|
|
AutomationController->RemoveCallbacks();
|
|
|
|
AutomationController->OnControllerReset().RemoveAll(this);
|
|
AutomationController->OnTestsRefreshed().RemoveAll(this);
|
|
AutomationController->OnTestsAvailable().RemoveAll(this);
|
|
AutomationController->OnTestsComplete().RemoveAll(this);
|
|
}
|
|
|
|
#if WITH_EDITOR
|
|
if ( FModuleManager::Get().IsModuleLoaded(TEXT("AssetRegistry")) )
|
|
{
|
|
FAssetRegistryModule& AssetRegistryModule = FModuleManager::GetModuleChecked<FAssetRegistryModule>(TEXT("AssetRegistry"));
|
|
AssetRegistryModule.Get().OnFileLoadProgressUpdated().RemoveAll(this);
|
|
}
|
|
#endif
|
|
|
|
TSharedPtr<IAutomationReport> PreviousSelectionLock = PreviousSelection.Pin();
|
|
if ( PreviousSelectionLock.IsValid() )
|
|
{
|
|
PreviousSelectionLock->OnSetResults.Unbind();
|
|
}
|
|
}
|
|
|
|
BEGIN_SLATE_FUNCTION_BUILD_OPTIMIZATION
|
|
void SAutomationWindow::Construct( const FArguments& InArgs, const IAutomationControllerManagerRef& InAutomationController, const TSharedRef<ISessionManager>& InSessionManager )
|
|
{
|
|
FAutomationWindowCommands::Register();
|
|
CreateCommands();
|
|
|
|
#if WITH_EDITOR
|
|
FAssetRegistryModule& AssetRegistryModule = FModuleManager::LoadModuleChecked<FAssetRegistryModule>(TEXT("AssetRegistry"));
|
|
AssetRegistryModule.Get().OnFileLoadProgressUpdated().AddSP(this, &SAutomationWindow::OnAssetRegistryFileLoadProgress);
|
|
#endif
|
|
|
|
TestPresetManager = MakeShareable(new FAutomationTestPresetManager());
|
|
TestPresetManager->LoadPresets();
|
|
bAddingTestPreset = false;
|
|
|
|
bHasChildTestSelected = false;
|
|
|
|
SessionManager = InSessionManager;
|
|
AutomationController = InAutomationController;
|
|
|
|
AutomationController->OnControllerReset().AddSP(this, &SAutomationWindow::OnRefreshTestCallback);
|
|
AutomationController->OnTestsRefreshed().AddSP(this, &SAutomationWindow::OnRefreshTestCallback);
|
|
AutomationController->OnTestsAvailable().AddSP(this, &SAutomationWindow::OnTestAvailableCallback);
|
|
AutomationController->OnTestsComplete().AddSP(this, &SAutomationWindow::OnTestsCompleteCallback);
|
|
|
|
AutomationControllerState = AutomationController->GetTestState();
|
|
|
|
//cache off reference to filtered reports
|
|
TArray <TSharedPtr <IAutomationReport> >& TestReports = AutomationController->GetReports();
|
|
|
|
// Create the search filter and set criteria
|
|
AutomationTextFilter = MakeShareable( new AutomationReportTextFilter( AutomationReportTextFilter::FItemToStringArray::CreateSP( this, &SAutomationWindow::PopulateReportSearchStrings ) ) );
|
|
AutomationGeneralFilter = MakeShareable( new FAutomationFilter() );
|
|
AutomationFilters = MakeShareable( new AutomationFilterCollection() );
|
|
AutomationFilters->Add( AutomationTextFilter );
|
|
AutomationFilters->Add( AutomationGeneralFilter );
|
|
|
|
bIsRequestingTests = false;
|
|
|
|
//make the widget for platforms
|
|
PlatformsHBox = SNew (SHorizontalBox);
|
|
|
|
TestTable = SNew(SAutomationTestTreeView< TSharedPtr< IAutomationReport > >)
|
|
.SelectionMode(ESelectionMode::Multi)
|
|
.TreeItemsSource( &TestReports )
|
|
// Generates the actual widget for a tree item
|
|
.OnGenerateRow( this, &SAutomationWindow::OnGenerateWidgetForTest )
|
|
// Gets children
|
|
.OnGetChildren(this, &SAutomationWindow::OnGetChildren)
|
|
// on recursive expansion (shift + click)
|
|
.OnSetExpansionRecursive(this, &SAutomationWindow::OnTestExpansionRecursive)
|
|
//on selection
|
|
.OnSelectionChanged(this, &SAutomationWindow::OnTestSelectionChanged)
|
|
// Allow for some spacing between items with a larger item height.
|
|
.ItemHeight(20.0f)
|
|
#if WITH_EDITOR
|
|
// If in editor - add a context menu for opening assets when in editor
|
|
.OnContextMenuOpening(this, &SAutomationWindow::HandleAutomationListContextMenuOpening)
|
|
#endif
|
|
.HeaderRow
|
|
(
|
|
SAssignNew(TestTableHeaderRow,SHeaderRow)
|
|
+ SHeaderRow::Column( AutomationTestWindowConstants::Title )
|
|
.FillWidth(0.80f)
|
|
[
|
|
SNew(SHorizontalBox)
|
|
+SHorizontalBox::Slot()
|
|
.AutoWidth()
|
|
.HAlign(HAlign_Center)
|
|
[
|
|
//global enable/disable check box
|
|
SAssignNew(HeaderCheckbox, SCheckBox)
|
|
.OnCheckStateChanged( this, &SAutomationWindow::HeaderCheckboxStateChange)
|
|
.ToolTipText( LOCTEXT( "Enable Disable Test", "Enable / Disable Test" ) )
|
|
]
|
|
+SHorizontalBox::Slot()
|
|
.AutoWidth()
|
|
.VAlign(VAlign_Center)
|
|
[
|
|
SNew( STextBlock )
|
|
.Text( LOCTEXT("TestName_Header", "Test Name") )
|
|
]
|
|
]
|
|
|
|
+ SHeaderRow::Column( AutomationTestWindowConstants::SmokeTest )
|
|
.FixedWidth( 50.0f )
|
|
.HAlignHeader(HAlign_Center)
|
|
.VAlignHeader(VAlign_Center)
|
|
.HAlignCell(HAlign_Center)
|
|
.VAlignCell(VAlign_Center)
|
|
[
|
|
//icon for the smoke test column
|
|
SNew(SImage)
|
|
.ColorAndOpacity(FLinearColor(1.0f, 1.0f, 1.0f, 0.4f))
|
|
.ToolTipText( LOCTEXT( "Smoke Test", "Smoke Test" ) )
|
|
.Image(FEditorStyle::GetBrush("Automation.SmokeTest"))
|
|
]
|
|
|
|
+ SHeaderRow::Column( AutomationTestWindowConstants::RequiredDeviceCount )
|
|
.FixedWidth(50.0f)
|
|
.HAlignHeader(HAlign_Center)
|
|
.VAlignHeader(VAlign_Center)
|
|
.HAlignCell(HAlign_Center)
|
|
.VAlignCell(VAlign_Center)
|
|
[
|
|
SNew( SImage )
|
|
.Image( FEditorStyle::GetBrush("Automation.ParticipantsWarning") )
|
|
.ToolTipText( LOCTEXT( "RequiredDeviceCountWarningToolTip", "Number of devices required." ) )
|
|
]
|
|
|
|
+ SHeaderRow::Column(AutomationTestWindowConstants::Timing)
|
|
.FixedWidth(100.0f)
|
|
.DefaultLabel(LOCTEXT("TestDurationRange", "Duration"))
|
|
|
|
+ SHeaderRow::Column( AutomationTestWindowConstants::Status )
|
|
.FixedWidth(50.0f)
|
|
[
|
|
//platform header placeholder
|
|
PlatformsHBox.ToSharedRef()
|
|
]
|
|
|
|
+ SHeaderRow::Column(AutomationTestWindowConstants::IsToBeSkipped)
|
|
.FillWidth(0.10f)
|
|
.DefaultLabel(LOCTEXT("Excluded", "Excluded"))
|
|
|
|
);
|
|
|
|
RequestedFilterComboList.Empty();
|
|
RequestedFilterComboList.Add(MakeShareable(new FString(TEXT("All Tests"))));
|
|
RequestedFilterComboList.Add(MakeShareable(new FString(TEXT("Smoke Tests"))));
|
|
RequestedFilterComboList.Add(MakeShareable(new FString(TEXT("Engine Tests"))));
|
|
RequestedFilterComboList.Add(MakeShareable(new FString(TEXT("Product Tests"))));
|
|
RequestedFilterComboList.Add(MakeShareable(new FString(TEXT("Performance Tests"))));
|
|
RequestedFilterComboList.Add(MakeShareable(new FString(TEXT("Stress Tests"))));
|
|
RequestedFilterComboList.Add(MakeShareable(new FString(TEXT("Standard Tests"))));
|
|
RequestedFilterComboList.Add(MakeShareable(new FString(TEXT("Negative Tests"))));
|
|
|
|
TSharedRef<SNotificationList> NotificationList = SNew(SNotificationList) .Visibility( EVisibility::HitTestInvisible );
|
|
|
|
//build the actual guts of the window
|
|
this->ChildSlot
|
|
[
|
|
SNew(SOverlay)
|
|
|
|
+ SOverlay::Slot()
|
|
[
|
|
SNew( SSplitter )
|
|
.IsEnabled(this, &SAutomationWindow::HandleMainContentIsEnabled)
|
|
.Orientation(Orient_Vertical)
|
|
|
|
+ SSplitter::Slot()
|
|
.Value(0.66f)
|
|
[
|
|
//automation test panel
|
|
SAssignNew( MenuBar, SVerticalBox )
|
|
|
|
//ACTIONS
|
|
+ SVerticalBox::Slot()
|
|
.AutoHeight()
|
|
[
|
|
SNew( SHorizontalBox )
|
|
|
|
+ SHorizontalBox::Slot()
|
|
.AutoWidth()
|
|
.HAlign(HAlign_Left)
|
|
.VAlign(VAlign_Center)
|
|
[
|
|
SAutomationWindow::MakeAutomationWindowToolBar( AutomationWindowActions.ToSharedRef(), SharedThis(this) )
|
|
]
|
|
]
|
|
|
|
+ SVerticalBox::Slot()
|
|
.FillHeight(1.0f)
|
|
.Padding(0.0f, 4.0f, 0.0f, 0.0f)
|
|
[
|
|
SNew(SOverlay)
|
|
+ SOverlay::Slot()
|
|
[
|
|
SNew(SBorder)
|
|
.BorderImage(this, &SAutomationWindow::GetTestBackgroundBorderImage)
|
|
.Padding(3)
|
|
[
|
|
SNew(SBox)
|
|
.Padding(4)
|
|
[
|
|
SNew(SVerticalBox)
|
|
|
|
+ SVerticalBox::Slot()
|
|
.AutoHeight()
|
|
.Padding(0.0f, 0.0f, 0.0f, 4.0f)
|
|
[
|
|
SNew(SHorizontalBox)
|
|
|
|
+ SHorizontalBox::Slot()
|
|
.AutoWidth()
|
|
.VAlign(VAlign_Center)
|
|
[
|
|
SNew(SBox)
|
|
.MinDesiredWidth(130.0f)
|
|
[
|
|
SAssignNew(RequestedFilterComboBox, SComboBox< TSharedPtr<FString> >)
|
|
.OptionsSource(&RequestedFilterComboList)
|
|
.InitiallySelectedItem(RequestedFilterComboList[6])
|
|
.OnGenerateWidget(this, &SAutomationWindow::GenerateRequestedFilterComboItem)
|
|
.OnSelectionChanged(this, &SAutomationWindow::HandleRequesteFilterChanged)
|
|
.ContentPadding(FMargin(4.0, 1.0f))
|
|
[
|
|
SNew(STextBlock)
|
|
.Text(this, &SAutomationWindow::GetRequestedFilterComboText)
|
|
]
|
|
]
|
|
]
|
|
|
|
+ SHorizontalBox::Slot()
|
|
.FillWidth(1.0f)
|
|
.VAlign(VAlign_Center)
|
|
.Padding(2.0f, 0, 0, 0)
|
|
[
|
|
SAssignNew(AutomationSearchBox, SSearchBox)
|
|
.ToolTipText(LOCTEXT("Search Tests", "Search Tests"))
|
|
.OnTextChanged(this, &SAutomationWindow::OnFilterTextChanged)
|
|
.IsEnabled(this, &SAutomationWindow::IsAutomationControllerIdle)
|
|
]
|
|
]
|
|
|
|
+ SVerticalBox::Slot()
|
|
.FillHeight(1.0f)
|
|
[
|
|
//the actual table full of tests
|
|
TestTable.ToSharedRef()
|
|
]
|
|
]
|
|
]
|
|
]
|
|
|
|
+ SOverlay::Slot()
|
|
.HAlign(HAlign_Center)
|
|
.VAlign(VAlign_Center)
|
|
[
|
|
SNew(SThrobber)
|
|
.Visibility(this, &SAutomationWindow::GetTestsUpdatingThrobberVisibility)
|
|
]
|
|
]
|
|
]
|
|
|
|
+ SSplitter::Slot()
|
|
.Value(0.33f)
|
|
[
|
|
SNew(SOverlay)
|
|
|
|
+ SOverlay::Slot()
|
|
[
|
|
SNew(SBox)
|
|
.Visibility(this, &SAutomationWindow::GetTestGraphVisibility)
|
|
[
|
|
//Graphical Results Panel
|
|
SNew( SVerticalBox )
|
|
|
|
+ SVerticalBox::Slot()
|
|
.AutoHeight()
|
|
[
|
|
SNew(SHorizontalBox)
|
|
|
|
+ SHorizontalBox::Slot()
|
|
.HAlign(HAlign_Left)
|
|
[
|
|
SNew(STextBlock)
|
|
.Text( LOCTEXT("AutomationTest_GraphicalResults", "Automation Test Graphical Results:"))
|
|
]
|
|
|
|
+ SHorizontalBox::Slot()
|
|
.HAlign(HAlign_Right)
|
|
.AutoWidth()
|
|
[
|
|
SNew(STextBlock)
|
|
.Text( LOCTEXT("AutomationTest_Display", "Display:"))
|
|
]
|
|
|
|
+ SHorizontalBox::Slot()
|
|
.HAlign(HAlign_Right)
|
|
.AutoWidth()
|
|
[
|
|
SNew(SCheckBox)
|
|
.Style(FCoreStyle::Get(), "RadioButton")
|
|
.IsChecked(this, &SAutomationWindow::HandleResultDisplayTypeIsChecked, EAutomationGrapicalDisplayType::DisplayName)
|
|
.OnCheckStateChanged(this, &SAutomationWindow::HandleResultDisplayTypeStateChanged, EAutomationGrapicalDisplayType::DisplayName)
|
|
[
|
|
SNew(STextBlock)
|
|
.Text( LOCTEXT("AutomationTest_GraphicalResultsDisplayName", "Name"))
|
|
]
|
|
]
|
|
|
|
+ SHorizontalBox::Slot()
|
|
.HAlign(HAlign_Right)
|
|
.AutoWidth()
|
|
[
|
|
SNew(SCheckBox)
|
|
.Style(FCoreStyle::Get(), "RadioButton")
|
|
.IsChecked(this, &SAutomationWindow::HandleResultDisplayTypeIsChecked, EAutomationGrapicalDisplayType::DisplayTime)
|
|
.OnCheckStateChanged(this, &SAutomationWindow::HandleResultDisplayTypeStateChanged, EAutomationGrapicalDisplayType::DisplayTime)
|
|
[
|
|
SNew(STextBlock)
|
|
.Text( LOCTEXT("AutomationTest_GraphicalResultsDisplayTime", "Time"))
|
|
]
|
|
]
|
|
]
|
|
|
|
+ SVerticalBox::Slot()
|
|
.FillHeight(1.0f)
|
|
[
|
|
SNew(SBorder)
|
|
[
|
|
SNew(SScrollBox)
|
|
|
|
+ SScrollBox::Slot()
|
|
[
|
|
SAssignNew(GraphicalResultBox, SAutomationGraphicalResultBox, InAutomationController)
|
|
]
|
|
]
|
|
]
|
|
]
|
|
]
|
|
|
|
+ SOverlay::Slot()
|
|
[
|
|
SNew(SBox)
|
|
.Visibility(this, &SAutomationWindow::GetTestLogVisibility)
|
|
[
|
|
//results panel
|
|
SNew( SVerticalBox )
|
|
+ SVerticalBox::Slot()
|
|
.AutoHeight()
|
|
[
|
|
SNew( STextBlock )
|
|
.Text( LOCTEXT("AutomationTest_Results", "Automation Test Results:") )
|
|
]
|
|
|
|
+ SVerticalBox::Slot()
|
|
.FillHeight(1.0f)
|
|
.Padding(0.0f, 4.0f, 0.0f, 0.0f)
|
|
[
|
|
//list of results for the selected test
|
|
SNew(SBorder)
|
|
.BorderImage(FEditorStyle::GetBrush("MessageLog.ListBorder"))
|
|
[
|
|
SNew(SScrollBox)
|
|
.Orientation(EOrientation::Orient_Horizontal)
|
|
+SScrollBox::Slot()
|
|
[
|
|
SAssignNew(LogListView, SListView<TSharedPtr<FAutomationOutputMessage> >)
|
|
.ItemHeight(18)
|
|
.ListItemsSource(&LogMessages)
|
|
.SelectionMode(ESelectionMode::Multi)
|
|
.OnGenerateRow(this, &SAutomationWindow::OnGenerateWidgetForLog)
|
|
.OnSelectionChanged(this, &SAutomationWindow::HandleLogListSelectionChanged)
|
|
]
|
|
]
|
|
]
|
|
|
|
+ SVerticalBox::Slot()
|
|
.AutoHeight()
|
|
.Padding(0.0f, 4.0f, 0.0f, 0.0f)
|
|
[
|
|
SNew(SBorder)
|
|
.BorderImage(FEditorStyle::GetBrush("ToolPanel.GroupBorder"))
|
|
.Padding(FMargin(8.0f, 6.0f))
|
|
[
|
|
// Add the command bar
|
|
SAssignNew(CommandBar, SAutomationWindowCommandBar, NotificationList)
|
|
.OnCopyLogClicked(this, &SAutomationWindow::HandleCommandBarCopyLogClicked)
|
|
]
|
|
]
|
|
]
|
|
]
|
|
]
|
|
]
|
|
|
|
+ SOverlay::Slot()
|
|
.HAlign( HAlign_Center )
|
|
.VAlign( VAlign_Center )
|
|
.Padding( 15.0f )
|
|
[
|
|
NotificationList
|
|
]
|
|
|
|
+ SOverlay::Slot()
|
|
.HAlign( HAlign_Center )
|
|
.VAlign( VAlign_Center )
|
|
.Padding( 15.0f )
|
|
[
|
|
SNew(SBorder)
|
|
.BorderImage(FEditorStyle::GetBrush("NotificationList.ItemBackground"))
|
|
.Padding(8.0f)
|
|
.Visibility(this, &SAutomationWindow::HandleSelectSessionOverlayVisibility)
|
|
[
|
|
SNew(STextBlock)
|
|
.Text(LOCTEXT("SelectSessionOverlayText", "Please select at least one instance from the Session Browser"))
|
|
]
|
|
]
|
|
];
|
|
|
|
SessionManager->OnCanSelectSession().AddSP( this, &SAutomationWindow::HandleSessionManagerCanSelectSession );
|
|
SessionManager->OnSelectedSessionChanged().AddSP( this, &SAutomationWindow::HandleSessionManagerSelectionChanged );
|
|
SessionManager->OnSessionInstanceUpdated().AddSP( this, &SAutomationWindow::HandleSessionManagerInstanceChanged );
|
|
|
|
FindWorkers();
|
|
}
|
|
END_SLATE_FUNCTION_BUILD_OPTIMIZATION
|
|
|
|
|
|
void SAutomationWindow::HandleResultDisplayTypeStateChanged( ECheckBoxState NewRadioState, EAutomationGrapicalDisplayType::Type NewDisplayType)
|
|
{
|
|
if (NewRadioState == ECheckBoxState::Checked)
|
|
{
|
|
GraphicalResultBox->SetDisplayType(NewDisplayType);
|
|
}
|
|
}
|
|
|
|
ECheckBoxState SAutomationWindow::HandleResultDisplayTypeIsChecked( EAutomationGrapicalDisplayType::Type InDisplayType ) const
|
|
{
|
|
return (GraphicalResultBox->GetDisplayType() == InDisplayType)
|
|
? ECheckBoxState::Checked
|
|
: ECheckBoxState::Unchecked;
|
|
}
|
|
|
|
const FSlateBrush* SAutomationWindow::GetTestBackgroundBorderImage() const
|
|
{
|
|
switch(TestBackgroundType)
|
|
{
|
|
case EAutomationTestBackgroundStyle::Game:
|
|
return FEditorStyle::GetBrush("AutomationWindow.GameGroupBorder");
|
|
|
|
case EAutomationTestBackgroundStyle::Editor:
|
|
return FEditorStyle::GetBrush("AutomationWindow.EditorGroupBorder");
|
|
|
|
case EAutomationTestBackgroundStyle::Unknown:
|
|
default:
|
|
return FEditorStyle::GetBrush("ToolPanel.GroupBorder");
|
|
}
|
|
}
|
|
|
|
void SAutomationWindow::CreateCommands()
|
|
{
|
|
check(!AutomationWindowActions.IsValid());
|
|
AutomationWindowActions = MakeShareable(new FUICommandList);
|
|
|
|
const FAutomationWindowCommands& Commands = FAutomationWindowCommands::Get();
|
|
FUICommandList& ActionList = *AutomationWindowActions;
|
|
|
|
ActionList.MapAction( Commands.RefreshTests,
|
|
FExecuteAction::CreateRaw( this, &SAutomationWindow::ListTests ),
|
|
FCanExecuteAction::CreateRaw( this, &SAutomationWindow::IsAutomationControllerIdle )
|
|
);
|
|
|
|
ActionList.MapAction( Commands.FindWorkers,
|
|
FExecuteAction::CreateRaw( this, &SAutomationWindow::FindWorkers ),
|
|
FCanExecuteAction::CreateRaw( this, &SAutomationWindow::IsAutomationControllerIdle )
|
|
);
|
|
|
|
ActionList.MapAction( Commands.ErrorFilter,
|
|
FExecuteAction::CreateRaw( this, &SAutomationWindow::OnToggleErrorFilter ),
|
|
FCanExecuteAction::CreateRaw( this, &SAutomationWindow::IsAutomationControllerIdle ),
|
|
FIsActionChecked::CreateRaw( this, &SAutomationWindow::IsErrorFilterOn )
|
|
);
|
|
|
|
ActionList.MapAction( Commands.WarningFilter,
|
|
FExecuteAction::CreateRaw( this, &SAutomationWindow::OnToggleWarningFilter ),
|
|
FCanExecuteAction::CreateRaw( this, &SAutomationWindow::IsAutomationControllerIdle ),
|
|
FIsActionChecked::CreateRaw( this, &SAutomationWindow::IsWarningFilterOn )
|
|
);
|
|
|
|
ActionList.MapAction( Commands.DeveloperDirectoryContent,
|
|
FExecuteAction::CreateRaw( this, &SAutomationWindow::OnToggleDeveloperDirectoryIncluded ),
|
|
FCanExecuteAction::CreateRaw( this, &SAutomationWindow::IsAutomationControllerIdle ),
|
|
FIsActionChecked::CreateRaw( this, &SAutomationWindow::IsDeveloperDirectoryIncluded )
|
|
);
|
|
|
|
ActionList.MapAction( Commands.ExcludedTestsFilter,
|
|
FExecuteAction::CreateRaw( this, &SAutomationWindow::OnToggleExcludedTestsFilter ),
|
|
FCanExecuteAction::CreateRaw( this, &SAutomationWindow::IsAutomationControllerIdle ),
|
|
FIsActionChecked::CreateRaw( this, &SAutomationWindow::IsExcludedTestsFilterOn )
|
|
);
|
|
|
|
// Added button for running the currently open level test.
|
|
#if WITH_EDITOR
|
|
ActionList.MapAction(Commands.RunLevelTest,
|
|
FExecuteAction::CreateRaw(this, &SAutomationWindow::OnRunLevelTest),
|
|
FCanExecuteAction::CreateRaw(this, &SAutomationWindow::CanExecuteRunLevelTest)
|
|
);
|
|
#endif // WITH_EDITOR
|
|
}
|
|
|
|
TSharedRef< SWidget > SAutomationWindow::MakeAutomationWindowToolBar( const TSharedRef<FUICommandList>& InCommandList, TSharedPtr<class SAutomationWindow> InAutomationWindow )
|
|
{
|
|
return InAutomationWindow->MakeAutomationWindowToolBar(InCommandList);
|
|
}
|
|
|
|
BEGIN_SLATE_FUNCTION_BUILD_OPTIMIZATION
|
|
TSharedRef< SWidget > SAutomationWindow::MakeAutomationWindowToolBar( const TSharedRef<FUICommandList>& InCommandList )
|
|
{
|
|
struct Local
|
|
{
|
|
static void FillToolbar(FToolBarBuilder& ToolbarBuilder, TSharedRef<SWidget> RunTests, TSharedRef<SWidget> PresetBox, TWeakPtr<class SAutomationWindow> InAutomationWindow)
|
|
{
|
|
ToolbarBuilder.BeginSection("Automation");
|
|
{
|
|
ToolbarBuilder.AddWidget( RunTests );
|
|
FUIAction DefaultAction;
|
|
ToolbarBuilder.AddComboButton(
|
|
DefaultAction,
|
|
FOnGetContent::CreateStatic( &SAutomationWindow::GenerateTestsOptionsMenuContent, InAutomationWindow ),
|
|
TAttribute<FText>(),
|
|
LOCTEXT( "TestOptionsToolTip", "Test Options" ),
|
|
FSlateIcon(FEditorStyle::GetStyleSetName(), "AutomationWindow.TestOptions"),
|
|
false);
|
|
|
|
// Added button for running the currently open level test.
|
|
#if WITH_EDITOR
|
|
ToolbarBuilder.AddToolBarButton(
|
|
FAutomationWindowCommands::Get().RunLevelTest,
|
|
NAME_None,
|
|
TAttribute<FText>(),
|
|
LOCTEXT("RunLevelTest_ToolTip", "If the currently loaded editor level is a test map, click this to select the test and run it immediately."),
|
|
FSlateIcon(FEditorStyle::GetStyleSetName(), "AutomationWindow.RunTests"));
|
|
#endif
|
|
|
|
ToolbarBuilder.AddToolBarButton( FAutomationWindowCommands::Get().RefreshTests );
|
|
ToolbarBuilder.AddToolBarButton( FAutomationWindowCommands::Get().FindWorkers );
|
|
}
|
|
ToolbarBuilder.EndSection();
|
|
ToolbarBuilder.BeginSection("Filters");
|
|
{
|
|
ToolbarBuilder.AddToolBarButton( FAutomationWindowCommands::Get().ErrorFilter );
|
|
ToolbarBuilder.AddToolBarButton( FAutomationWindowCommands::Get().WarningFilter );
|
|
ToolbarBuilder.AddToolBarButton( FAutomationWindowCommands::Get().DeveloperDirectoryContent );
|
|
ToolbarBuilder.AddToolBarButton( FAutomationWindowCommands::Get().ExcludedTestsFilter);
|
|
}
|
|
ToolbarBuilder.EndSection();
|
|
ToolbarBuilder.BeginSection("GroupFlags");
|
|
{
|
|
ToolbarBuilder.AddComboButton(
|
|
FUIAction(),
|
|
FOnGetContent::CreateStatic( &SAutomationWindow::GenerateGroupOptionsMenuContent, InAutomationWindow ),
|
|
LOCTEXT( "GroupOptions_Label", "Device Groups" ),
|
|
LOCTEXT( "GroupOptionsToolTip", "Device Group Options" ),
|
|
FSlateIcon(FEditorStyle::GetStyleSetName(), "AutomationWindow.GroupSettings"));
|
|
}
|
|
ToolbarBuilder.EndSection();
|
|
ToolbarBuilder.BeginSection("Presets");
|
|
{
|
|
ToolbarBuilder.AddWidget( PresetBox );
|
|
}
|
|
ToolbarBuilder.EndSection();
|
|
}
|
|
};
|
|
|
|
TSharedRef<SWidget> RunTests =
|
|
SNew( SButton )
|
|
.ButtonStyle( FEditorStyle::Get(), "ToggleButton" )
|
|
.ToolTipText( LOCTEXT( "StartStop Tests", "Start / Stop tests" ) )
|
|
.OnClicked( this, &SAutomationWindow::RunTests )
|
|
.IsEnabled( this, &SAutomationWindow::IsAutomationRunButtonEnabled )
|
|
.ContentPadding(0)
|
|
[
|
|
SNew(SHorizontalBox)
|
|
+ SHorizontalBox::Slot()
|
|
.FillWidth(1)
|
|
.VAlign(VAlign_Center)
|
|
[
|
|
SNew( SVerticalBox )
|
|
+ SVerticalBox::Slot()
|
|
.AutoHeight()
|
|
.HAlign( HAlign_Center )
|
|
[
|
|
SNew( SOverlay )
|
|
+SOverlay::Slot()
|
|
[
|
|
SNew( SImage )
|
|
.Image( this, &SAutomationWindow::GetRunAutomationIcon )
|
|
]
|
|
+SOverlay::Slot()
|
|
.HAlign(HAlign_Right)
|
|
.VAlign(VAlign_Bottom)
|
|
[
|
|
SNew( STextBlock )
|
|
.Text( this, &SAutomationWindow::OnGetNumEnabledTestsString )
|
|
.ColorAndOpacity( FLinearColor::White )
|
|
.ShadowOffset( FVector2D::UnitVector )
|
|
.Font( FEditorStyle::GetFontStyle( FName( "ToggleButton.LabelFont" ) ) )
|
|
]
|
|
]
|
|
+ SVerticalBox::Slot()
|
|
.AutoHeight()
|
|
.HAlign( HAlign_Center )
|
|
[
|
|
SNew( STextBlock )
|
|
.Visibility( this, &SAutomationWindow::GetLargeToolBarVisibility )
|
|
.Text( this, &SAutomationWindow::GetRunAutomationLabel )
|
|
.Font( FEditorStyle::GetFontStyle( FName( "ToggleButton.LabelFont" ) ) )
|
|
.ColorAndOpacity(FLinearColor::White)
|
|
.ShadowOffset( FVector2D::UnitVector )
|
|
]
|
|
]
|
|
];
|
|
|
|
TSharedRef<SWidget> TestPresets =
|
|
SNew( SVerticalBox )
|
|
+SVerticalBox::Slot()
|
|
.FillHeight(0.75f)
|
|
.VAlign(VAlign_Bottom)
|
|
.HAlign(HAlign_Left)
|
|
[
|
|
SNew( SHorizontalBox )
|
|
+SHorizontalBox::Slot()
|
|
.AutoWidth()
|
|
.Padding(2.0f)
|
|
.VAlign(VAlign_Bottom)
|
|
[
|
|
SNew( STextBlock )
|
|
.Text( LOCTEXT("AutomationPresetLabel", "Preset:") )
|
|
.IsEnabled( this, &SAutomationWindow::IsAutomationControllerIdle )
|
|
]
|
|
]
|
|
+SVerticalBox::Slot()
|
|
.AutoHeight()
|
|
.VAlign(VAlign_Bottom)
|
|
[
|
|
SNew( SHorizontalBox )
|
|
+SHorizontalBox::Slot()
|
|
.AutoWidth()
|
|
[
|
|
//Preset Combo / Text
|
|
SNew(SOverlay)
|
|
+SOverlay::Slot()
|
|
[
|
|
SNew(SHorizontalBox)
|
|
.Visibility(this,&SAutomationWindow::HandlePresetComboVisibility)
|
|
+SHorizontalBox::Slot()
|
|
.FillWidth(1.0)
|
|
[
|
|
SAssignNew( PresetComboBox, SComboBox< TSharedPtr<FAutomationTestPreset> > )
|
|
.OptionsSource( &TestPresetManager->GetAllPresets() )
|
|
.OnGenerateWidget( this, &SAutomationWindow::GeneratePresetComboItem )
|
|
.OnSelectionChanged( this, &SAutomationWindow::HandlePresetChanged )
|
|
.IsEnabled(this, &SAutomationWindow::IsAutomationControllerIdle)
|
|
[
|
|
SNew( STextBlock )
|
|
.Text( this, &SAutomationWindow::GetPresetComboText )
|
|
]
|
|
]
|
|
]
|
|
+SOverlay::Slot()
|
|
[
|
|
SNew(SHorizontalBox)
|
|
.Visibility(this,&SAutomationWindow::HandlePresetTextVisibility)
|
|
+SHorizontalBox::Slot()
|
|
.FillWidth(1.0)
|
|
[
|
|
SAssignNew(PresetTextBox, SEditableTextBox)
|
|
.OnTextCommitted(this, &SAutomationWindow::HandlePresetTextCommited)
|
|
.IsEnabled(this, &SAutomationWindow::IsAutomationControllerIdle)
|
|
]
|
|
]
|
|
]
|
|
|
|
//New button
|
|
+SHorizontalBox::Slot()
|
|
.AutoWidth()
|
|
[
|
|
SNew( SButton )
|
|
.ButtonStyle( FEditorStyle::Get(), "NoBorder" )
|
|
.OnClicked( this, &SAutomationWindow::HandleNewPresetClicked )
|
|
.ToolTipText( LOCTEXT("AutomationPresetNewButtonTooltip", "Create a new preset") )
|
|
.IsEnabled(this, &SAutomationWindow::IsAddButtonEnabled)
|
|
.Content()
|
|
[
|
|
SNew(SImage)
|
|
.Image(FEditorStyle::Get().GetBrush("AutomationWindow.PresetNew"))
|
|
]
|
|
]
|
|
|
|
//Save button
|
|
+SHorizontalBox::Slot()
|
|
.AutoWidth()
|
|
[
|
|
SNew( SButton )
|
|
.ButtonStyle( FEditorStyle::Get(), "NoBorder" )
|
|
.OnClicked( this, &SAutomationWindow::HandleSavePresetClicked )
|
|
.ToolTipText( LOCTEXT("AutomationPresetSaveButtonTooltip", "Save the current test list") )
|
|
.IsEnabled(this, &SAutomationWindow::IsSaveButtonEnabled)
|
|
.Content()
|
|
[
|
|
SNew(SImage)
|
|
.Image(FEditorStyle::Get().GetBrush("AutomationWindow.PresetSave"))
|
|
]
|
|
]
|
|
|
|
//Remove button
|
|
+ SHorizontalBox::Slot()
|
|
.AutoWidth()
|
|
[
|
|
// remove button
|
|
SNew(SButton)
|
|
.ButtonStyle( FEditorStyle::Get(), "NoBorder" )
|
|
.OnClicked( this, &SAutomationWindow::HandleRemovePresetClicked )
|
|
.ToolTipText(LOCTEXT("AutomationPresetRemoveButtonTooltip", "Remove the selected preset"))
|
|
.IsEnabled(this, &SAutomationWindow::IsRemoveButtonEnabled)
|
|
.Content()
|
|
[
|
|
SNew(SImage)
|
|
.Image(FEditorStyle::Get().GetBrush("AutomationWindow.PresetRemove"))
|
|
]
|
|
]
|
|
];
|
|
|
|
FToolBarBuilder ToolbarBuilder( InCommandList, FMultiBoxCustomization::None );
|
|
TWeakPtr<SAutomationWindow> AutomationWindow = SharedThis(this);
|
|
Local::FillToolbar(ToolbarBuilder, RunTests, TestPresets, AutomationWindow);
|
|
|
|
// Create the tool bar!
|
|
return
|
|
SNew( SHorizontalBox )
|
|
+SHorizontalBox::Slot()
|
|
.AutoWidth()
|
|
[
|
|
SNew( SBorder )
|
|
.Padding(0)
|
|
.BorderImage( FEditorStyle::GetBrush("NoBorder") )
|
|
.IsEnabled( FSlateApplication::Get().GetNormalExecutionAttribute() )
|
|
[
|
|
ToolbarBuilder.MakeWidget()
|
|
]
|
|
];
|
|
}
|
|
END_SLATE_FUNCTION_BUILD_OPTIMIZATION
|
|
|
|
EVisibility SAutomationWindow::HandlePresetComboVisibility( ) const
|
|
{
|
|
return bAddingTestPreset ? EVisibility::Hidden : EVisibility::Visible;
|
|
}
|
|
|
|
EVisibility SAutomationWindow::HandlePresetTextVisibility( ) const
|
|
{
|
|
return bAddingTestPreset ? EVisibility::Visible : EVisibility::Hidden;
|
|
}
|
|
|
|
bool SAutomationWindow::IsAddButtonEnabled() const
|
|
{
|
|
return !bAddingTestPreset && IsAutomationControllerIdle();
|
|
}
|
|
|
|
bool SAutomationWindow::IsSaveButtonEnabled() const
|
|
{
|
|
return (!bAddingTestPreset && SelectedPreset.IsValid() && IsAutomationControllerIdle());
|
|
}
|
|
|
|
bool SAutomationWindow::IsRemoveButtonEnabled() const
|
|
{
|
|
return (!bAddingTestPreset && SelectedPreset.IsValid() && IsAutomationControllerIdle());
|
|
}
|
|
|
|
void SAutomationWindow::HandlePresetTextCommited( const FText& CommittedText, ETextCommit::Type CommitType )
|
|
{
|
|
if( CommitType == ETextCommit::OnEnter )
|
|
{
|
|
bAddingTestPreset = false;
|
|
if ( CommittedText.IsEmpty() )
|
|
{
|
|
return;
|
|
}
|
|
|
|
TArray<FString> EnabledTests;
|
|
AutomationController->GetEnabledTestNames(EnabledTests);
|
|
AutomationPresetPtr NewPreset = TestPresetManager->AddNewPreset(CommittedText, EnabledTests);
|
|
if ( NewPreset.IsValid() )
|
|
{
|
|
PresetComboBox->SetSelectedItem(NewPreset);
|
|
SelectedPreset = NewPreset;
|
|
|
|
PresetTextBox->SetText(FText());
|
|
}
|
|
}
|
|
else if( CommitType == ETextCommit::OnCleared || CommitType == ETextCommit::OnUserMovedFocus )
|
|
{
|
|
if( bAddingTestPreset )
|
|
{
|
|
bAddingTestPreset = false;
|
|
SelectedPreset = nullptr;
|
|
PresetComboBox->ClearSelection();
|
|
PresetTextBox->SetText(FText());
|
|
}
|
|
}
|
|
}
|
|
|
|
void SAutomationWindow::HandlePresetChanged( TSharedPtr<FAutomationTestPreset> Item, ESelectInfo::Type SelectInfo )
|
|
{
|
|
if( Item.IsValid() )
|
|
{
|
|
SelectedPreset = Item;
|
|
AutomationController->SetEnabledTests(Item->GetEnabledTests());
|
|
TestTable->RequestTreeRefresh();
|
|
|
|
//Expand selected items
|
|
TestTable->ClearExpandedItems();
|
|
TArray< TSharedPtr< IAutomationReport > >& TestReports = AutomationController->GetReports();
|
|
for( int32 Index = 0; Index < TestReports.Num(); Index++ )
|
|
{
|
|
ExpandEnabledTests(TestReports[Index]);
|
|
}
|
|
}
|
|
else
|
|
{
|
|
SelectedPreset.Reset();
|
|
|
|
TArray<FString> EnabledTests;
|
|
AutomationController->SetEnabledTests(EnabledTests);
|
|
TestTable->ClearExpandedItems();
|
|
TestTable->RequestTreeRefresh();
|
|
}
|
|
}
|
|
|
|
void SAutomationWindow::HandleRequesteFilterChanged(TSharedPtr<FString> Item, ESelectInfo::Type SelectInfo)
|
|
{
|
|
const int32 EntryIndex = RequestedFilterComboList.Find(Item);
|
|
uint32 NewRequestedFlags = EAutomationTestFlags::SmokeFilter;
|
|
|
|
switch (EntryIndex)
|
|
{
|
|
case 0: // "All Tests"
|
|
NewRequestedFlags = EAutomationTestFlags::FilterMask;
|
|
break;
|
|
case 1: // "Smoke Tests"
|
|
NewRequestedFlags = EAutomationTestFlags::SmokeFilter;
|
|
break;
|
|
case 2: // "Engine Tests"
|
|
NewRequestedFlags = EAutomationTestFlags::EngineFilter;
|
|
break;
|
|
case 3: // "Product Tests"
|
|
NewRequestedFlags = EAutomationTestFlags::ProductFilter;
|
|
break;
|
|
case 4: // "Performance Tests"
|
|
NewRequestedFlags = EAutomationTestFlags::PerfFilter;
|
|
break;
|
|
case 5: // "Stress Tests"
|
|
NewRequestedFlags = EAutomationTestFlags::StressFilter;
|
|
break;
|
|
case 6: // "Standard Tests"
|
|
NewRequestedFlags = EAutomationTestFlags::SmokeFilter | EAutomationTestFlags::EngineFilter | EAutomationTestFlags::ProductFilter | EAutomationTestFlags::PerfFilter;
|
|
break;
|
|
case 7: // "Negative Tests"
|
|
NewRequestedFlags = EAutomationTestFlags::NegativeFilter;
|
|
break;
|
|
}
|
|
AutomationController->SetRequestedTestFlags(NewRequestedFlags);
|
|
}
|
|
|
|
|
|
void SAutomationWindow::ExpandEnabledTests( TSharedPtr< IAutomationReport > InReport )
|
|
{
|
|
// Expand node if the report is enabled or contains an enabled test
|
|
TestTable->SetItemExpansion( InReport, InReport->IsEnabled() || InReport->GetEnabledTestsNum() > 0 );
|
|
|
|
// Iterate through the child nodes to see if they should be expanded
|
|
TArray<TSharedPtr< IAutomationReport > > Reports = InReport->GetFilteredChildren();
|
|
|
|
for ( int32 ChildItem = 0; ChildItem < Reports.Num(); ChildItem++ )
|
|
{
|
|
ExpandEnabledTests( Reports[ ChildItem ] );
|
|
}
|
|
}
|
|
|
|
FReply SAutomationWindow::HandleNewPresetClicked()
|
|
{
|
|
bAddingTestPreset = true;
|
|
return FReply::Handled().SetUserFocus(PresetTextBox.ToSharedRef(), EFocusCause::SetDirectly);
|
|
}
|
|
|
|
FReply SAutomationWindow::HandleSavePresetClicked()
|
|
{
|
|
if(SelectedPreset.IsValid())
|
|
{
|
|
TArray<FString> EnabledTests;
|
|
AutomationController->GetEnabledTestNames(EnabledTests);
|
|
SelectedPreset->SetEnabledTests(EnabledTests);
|
|
TestPresetManager->SavePreset(SelectedPreset.ToSharedRef());
|
|
}
|
|
return FReply::Handled();
|
|
}
|
|
|
|
FReply SAutomationWindow::HandleRemovePresetClicked()
|
|
{
|
|
if(SelectedPreset.IsValid())
|
|
{
|
|
TestPresetManager->RemovePreset(SelectedPreset.ToSharedRef());
|
|
SelectedPreset = nullptr;
|
|
PresetComboBox->ClearSelection();
|
|
}
|
|
return FReply::Handled();
|
|
}
|
|
|
|
FText SAutomationWindow::GetPresetComboText() const
|
|
{
|
|
if ( SelectedPreset.IsValid() )
|
|
{
|
|
return SelectedPreset->GetName();
|
|
}
|
|
else
|
|
{
|
|
return LOCTEXT("AutomationPresetComboLabel", "None");
|
|
}
|
|
}
|
|
|
|
FText SAutomationWindow::GetRequestedFilterComboText() const
|
|
{
|
|
if (RequestedFilterComboBox->GetSelectedItem().IsValid())
|
|
{
|
|
return FText::FromString(*RequestedFilterComboBox->GetSelectedItem());
|
|
}
|
|
else
|
|
{
|
|
return LOCTEXT("AutomationRequestedFilterComboLabel", "All Tests");
|
|
}
|
|
}
|
|
|
|
|
|
TSharedRef<SWidget> SAutomationWindow::GeneratePresetComboItem(TSharedPtr<FAutomationTestPreset> InItem)
|
|
{
|
|
if ( InItem.IsValid() )
|
|
{
|
|
return SNew(STextBlock)
|
|
.Text(InItem->GetName());
|
|
}
|
|
else
|
|
{
|
|
return SNew(STextBlock)
|
|
.Text(LOCTEXT("AutomationPreset_None", "None"));
|
|
}
|
|
}
|
|
|
|
TSharedRef<SWidget> SAutomationWindow::GenerateRequestedFilterComboItem(TSharedPtr<FString> InItem)
|
|
{
|
|
return SNew(STextBlock)
|
|
.Text(FText::FromString(*InItem));
|
|
}
|
|
|
|
TSharedRef< SWidget > SAutomationWindow::GenerateGroupOptionsMenuContent( TWeakPtr<class SAutomationWindow> InAutomationWindow )
|
|
{
|
|
TSharedPtr<SAutomationWindow> AutomationWindow(InAutomationWindow.Pin());
|
|
if( AutomationWindow.IsValid() )
|
|
{
|
|
return AutomationWindow->GenerateGroupOptionsMenuContent();
|
|
}
|
|
|
|
//Return empty menu
|
|
FMenuBuilder MenuBuilder( true, nullptr );
|
|
MenuBuilder.BeginSection("AutomationWindowGroupOptions", LOCTEXT("DeviceGroupOptions", "Device Group Options"));
|
|
MenuBuilder.EndSection();
|
|
return MenuBuilder.MakeWidget();
|
|
}
|
|
|
|
TSharedRef< SWidget > SAutomationWindow::GenerateGroupOptionsMenuContent( )
|
|
{
|
|
const bool bShouldCloseWindowAfterMenuSelection = true;
|
|
FMenuBuilder MenuBuilder( bShouldCloseWindowAfterMenuSelection, AutomationWindowActions );
|
|
const uint32 NumFlags = EAutomationDeviceGroupTypes::Max;
|
|
TSharedPtr<SWidget> FlagWidgets[NumFlags];
|
|
for( int32 i=0; i<NumFlags; i++ )
|
|
{
|
|
FlagWidgets[i] =
|
|
SNew(SCheckBox)
|
|
.IsChecked(this, &SAutomationWindow::IsDeviceGroupCheckBoxIsChecked, i)
|
|
.OnCheckStateChanged(this, &SAutomationWindow::HandleDeviceGroupCheckStateChanged, i)
|
|
.Padding(FMargin(4.0f, 0.0f))
|
|
.ToolTipText(EAutomationDeviceGroupTypes::ToDescription((EAutomationDeviceGroupTypes::Type)i))
|
|
.IsEnabled( this, &SAutomationWindow::IsAutomationControllerIdle )
|
|
.Content()
|
|
[
|
|
SNew(STextBlock)
|
|
.Text(EAutomationDeviceGroupTypes::ToName((EAutomationDeviceGroupTypes::Type)i))
|
|
];
|
|
}
|
|
|
|
MenuBuilder.BeginSection("AutomationWindowGroupDevices", LOCTEXT("GroupTypeOptions", "Group Types"));
|
|
{
|
|
for( int32 i=0; i<NumFlags;i++ )
|
|
{
|
|
MenuBuilder.AddWidget(FlagWidgets[i].ToSharedRef(),FText::GetEmpty());
|
|
}
|
|
}
|
|
|
|
return MenuBuilder.MakeWidget();
|
|
}
|
|
|
|
/** Returns if full size screen shots are enabled */
|
|
ECheckBoxState SAutomationWindow::IsDeviceGroupCheckBoxIsChecked(const int32 DeviceGroupFlag) const
|
|
{
|
|
return AutomationController->IsDeviceGroupFlagSet((EAutomationDeviceGroupTypes::Type)DeviceGroupFlag) ? ECheckBoxState::Checked : ECheckBoxState::Unchecked;
|
|
}
|
|
/** Toggles if we are collecting full size screenshots */
|
|
void SAutomationWindow::HandleDeviceGroupCheckStateChanged(ECheckBoxState CheckBoxState, const int32 DeviceGroupFlag)
|
|
{
|
|
//Update the device groups
|
|
AutomationController->ToggleDeviceGroupFlag((EAutomationDeviceGroupTypes::Type)DeviceGroupFlag);
|
|
AutomationController->UpdateDeviceGroups();
|
|
|
|
//Update header
|
|
RebuildPlatformIcons();
|
|
|
|
//Need to force the tree to do a full refresh here because the reports have changed but the tree will keep using cached data.
|
|
TestTable->ReCreateTreeView();
|
|
}
|
|
|
|
TSharedRef< SWidget > SAutomationWindow::GenerateTestsOptionsMenuContent( TWeakPtr<class SAutomationWindow> InAutomationWindow )
|
|
{
|
|
TSharedPtr<SAutomationWindow> AutomationWindow(InAutomationWindow.Pin());
|
|
if( AutomationWindow.IsValid() )
|
|
{
|
|
return AutomationWindow->GenerateTestsOptionsMenuContent();
|
|
}
|
|
|
|
//Return empty menu
|
|
FMenuBuilder MenuBuilder( true, nullptr );
|
|
MenuBuilder.BeginSection("AutomationWindowRunTest", LOCTEXT("RunTestOptions", "Advanced Settings"));
|
|
MenuBuilder.EndSection();
|
|
return MenuBuilder.MakeWidget();
|
|
}
|
|
|
|
TSharedRef< SWidget > SAutomationWindow::GenerateTestsOptionsMenuContent( )
|
|
{
|
|
const bool bShouldCloseWindowAfterMenuSelection = true;
|
|
FMenuBuilder MenuBuilder( bShouldCloseWindowAfterMenuSelection, AutomationWindowActions );
|
|
TSharedRef<SWidget> NumTests =
|
|
SNew(SBox)
|
|
.WidthOverride( 200.0f )
|
|
[
|
|
SNew( SHorizontalBox )
|
|
+SHorizontalBox::Slot()
|
|
.Padding(0.0f,0.0f,4.0f, 0.0f)
|
|
.AutoWidth()
|
|
[
|
|
SNew( STextBlock )
|
|
.Text( LOCTEXT("NumTestsToolTip", "Number of runs:") )
|
|
]
|
|
+SHorizontalBox::Slot()
|
|
.FillWidth(1.f)
|
|
[
|
|
SNew(SSpinBox<int32>)
|
|
.MinValue(1)
|
|
.MaxValue(1000)
|
|
.MinSliderValue(1)
|
|
.MaxSliderValue(1000)
|
|
.Value(this,&SAutomationWindow::GetRepeatCount)
|
|
.OnValueChanged(this,&SAutomationWindow::OnChangeRepeatCount)
|
|
.IsEnabled( this, &SAutomationWindow::IsAutomationControllerIdle )
|
|
]
|
|
|
|
];
|
|
|
|
|
|
TSharedRef<SWidget> SendAnalyticsWidget =
|
|
SNew(SCheckBox)
|
|
.IsChecked(this, &SAutomationWindow::IsSendAnalyticsCheckBoxChecked)
|
|
.OnCheckStateChanged(this, &SAutomationWindow::HandleSendAnalyticsBoxCheckStateChanged)
|
|
.Padding(FMargin(4.0f, 0.0f))
|
|
.ToolTipText(LOCTEXT("AutomationSendAnalyticsTip", "If checked, tests send analytics results to the backend"))
|
|
.IsEnabled(this, &SAutomationWindow::IsAutomationControllerIdle)
|
|
.Content()
|
|
[
|
|
SNew(STextBlock)
|
|
.Text(LOCTEXT("AutomationSendAnalyticsText", "Enable analytics"))
|
|
];
|
|
|
|
|
|
MenuBuilder.BeginSection("AutomationWindowRunTest", LOCTEXT("RunTestOptions", "Advanced Settings"));
|
|
{
|
|
MenuBuilder.AddWidget(NumTests, FText::GetEmpty());
|
|
MenuBuilder.AddWidget(SendAnalyticsWidget, FText::GetEmpty());
|
|
}
|
|
MenuBuilder.EndSection();
|
|
|
|
return MenuBuilder.MakeWidget();
|
|
}
|
|
|
|
ECheckBoxState SAutomationWindow::IsSendAnalyticsCheckBoxChecked() const
|
|
{
|
|
return AutomationController->IsSendAnalytics() ? ECheckBoxState::Checked : ECheckBoxState::Unchecked;
|
|
}
|
|
|
|
void SAutomationWindow::HandleSendAnalyticsBoxCheckStateChanged(ECheckBoxState CheckBoxState)
|
|
{
|
|
AutomationController->SetSendAnalytics(CheckBoxState == ECheckBoxState::Checked);
|
|
}
|
|
|
|
TArray<FString> SAutomationWindow::SaveExpandedTestNames(TSet<TSharedPtr<IAutomationReport>> ExpandedItems)
|
|
{
|
|
TArray<FString> ExpandedItemsNames;
|
|
for ( TSharedPtr<IAutomationReport> ExpandedItem : ExpandedItems )
|
|
{
|
|
ExpandedItemsNames.Add(ExpandedItem->GetDisplayNameWithDecoration());
|
|
}
|
|
return ExpandedItemsNames;
|
|
}
|
|
|
|
// Expanded the given item if its name is in the array of strings given.
|
|
void SAutomationWindow::ExpandItemsInList(TSharedPtr<SAutomationTestTreeView<TSharedPtr<IAutomationReport>>> InTestTable, TSharedPtr<IAutomationReport> InReport, TArray<FString> ItemsToExpand)
|
|
{
|
|
InTestTable->SetItemExpansion(InReport, ItemsToExpand.Contains(InReport->GetDisplayNameWithDecoration()));
|
|
|
|
TArray<TSharedPtr<IAutomationReport>> ChildReports = InReport->GetFilteredChildren();
|
|
|
|
for ( int32 Index = 0; Index < ChildReports.Num(); Index++ )
|
|
{
|
|
ExpandItemsInList(InTestTable, ChildReports[Index], ItemsToExpand);
|
|
}
|
|
}
|
|
|
|
// Only valid in the editor
|
|
#if WITH_EDITOR
|
|
TSharedPtr<SWidget> SAutomationWindow::HandleAutomationListContextMenuOpening()
|
|
{
|
|
TArray< TSharedPtr<IAutomationReport> >SelectedReport = TestTable->GetSelectedItems();
|
|
|
|
TArray<FString> TestNames;
|
|
TArray<FString> AssetNames;
|
|
for (TSharedPtr<IAutomationReport> Report : SelectedReport)
|
|
{
|
|
if (Report.IsValid())
|
|
{
|
|
FString TestName = Report->GetFullTestPath();
|
|
if (!TestName.IsEmpty())
|
|
{
|
|
TestNames.Add(MoveTemp(TestName));
|
|
}
|
|
FString Param = Report->GetTestParameter();
|
|
if (Param.StartsWith(TEXT("/")))
|
|
{
|
|
// Assume that if parameter start with a "/", it should be an asset
|
|
AssetNames.Add(MoveTemp(Param));
|
|
}
|
|
}
|
|
}
|
|
|
|
if (AssetNames.Num() || TestNames.Num())
|
|
{
|
|
return SNew(SAutomationTestItemContextMenu, AssetNames, TestNames);
|
|
}
|
|
|
|
return nullptr;
|
|
}
|
|
|
|
void SAutomationWindow::RunSelectedTests()
|
|
{
|
|
AutomationController->SetVisibleTestsEnabled(false);
|
|
SetAllSelectedTestsChecked(true);
|
|
RunTests();
|
|
}
|
|
|
|
namespace
|
|
{
|
|
bool MakeMapPathUrl(FString& InPath)
|
|
{
|
|
if ( FPaths::MakePathRelativeTo(InPath, *FPaths::ProjectContentDir()) )
|
|
{
|
|
InPath.InsertAt(0, TEXT("/Game/"));
|
|
InPath.RemoveFromEnd(TEXT(".umap"));
|
|
return true;
|
|
}
|
|
return false;
|
|
}
|
|
|
|
/**
|
|
* Kind of a hack - this requires that we know we group all the map tests coming from blueprints under "Functional Tests"
|
|
*/
|
|
TSharedPtr<IAutomationReport> GetFunctionalTestsReport(const TArray< TSharedPtr< IAutomationReport > >& TestReports)
|
|
{
|
|
for ( auto& Report : TestReports )
|
|
{
|
|
if ( Report->GetDisplayName() == TEXT("Functional Tests") )
|
|
{
|
|
return Report;
|
|
}
|
|
|
|
auto FoundInChild = GetFunctionalTestsReport(Report->GetChildReports());
|
|
if ( FoundInChild.IsValid() )
|
|
{
|
|
return FoundInChild;
|
|
}
|
|
}
|
|
return TSharedPtr<IAutomationReport>();
|
|
}
|
|
|
|
void FindReportByGameRelativeAssetPath(const TSharedPtr<IAutomationReport>& RootReport, const FString& AssetRelativePath, TArray<TSharedPtr<IAutomationReport>>& OutLevelReports)
|
|
{
|
|
FString TestAssetRelativePath(RootReport->GetTestParameter());
|
|
|
|
if ( TestAssetRelativePath.StartsWith(AssetRelativePath) )
|
|
{
|
|
OutLevelReports.Add(RootReport);
|
|
}
|
|
else
|
|
{
|
|
// Branch node
|
|
for ( auto ChildReport : RootReport->GetChildReports() )
|
|
{
|
|
FindReportByGameRelativeAssetPath(ChildReport, AssetRelativePath, OutLevelReports);
|
|
}
|
|
}
|
|
}
|
|
} // namespace
|
|
|
|
void SAutomationWindow::FindTestReportsForCurrentEditorLevel(TArray<TSharedPtr<IAutomationReport>>& OutLevelReports)
|
|
{
|
|
// Find the current map path
|
|
if ( GWorld && GWorld->GetCurrentLevel() )
|
|
{
|
|
FString MapUrl(FEditorFileUtils::GetFilename(GWorld->GetCurrentLevel()));
|
|
if ( MakeMapPathUrl(MapUrl) )
|
|
{
|
|
auto FunctionTestsReport = GetFunctionalTestsReport(AutomationController->GetReports());
|
|
if ( FunctionTestsReport.IsValid() )
|
|
{
|
|
FindReportByGameRelativeAssetPath(FunctionTestsReport, MapUrl, OutLevelReports);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
bool SAutomationWindow::CanExecuteRunLevelTest()
|
|
{
|
|
return IsAutomationControllerIdle();
|
|
}
|
|
|
|
void SAutomationWindow::OnRunLevelTest()
|
|
{
|
|
TArray<TSharedPtr<IAutomationReport>> LevelReports;
|
|
FindTestReportsForCurrentEditorLevel(LevelReports);
|
|
|
|
if ( LevelReports.Num() > 0 )
|
|
{
|
|
TestTable->ClearSelection();
|
|
for ( auto& LevelReport : LevelReports )
|
|
{
|
|
TestTable->SetItemSelection(LevelReport, true);
|
|
}
|
|
|
|
ScrollToTest(LevelReports[0]);
|
|
RunSelectedTests();
|
|
}
|
|
}
|
|
|
|
void SAutomationWindow::ScrollToTest(TSharedPtr<IAutomationReport> InReport)
|
|
{
|
|
auto& RootReports = AutomationController->GetReports();
|
|
for ( auto ChildReport : RootReports )
|
|
{
|
|
auto ShouldExpand = ExpandToTest(ChildReport, InReport);
|
|
TestTable->SetItemExpansion(ChildReport, ShouldExpand);
|
|
}
|
|
|
|
TestTable->RequestScrollIntoView(InReport);
|
|
}
|
|
|
|
bool SAutomationWindow::ExpandToTest(TSharedPtr<IAutomationReport> InRoot, TSharedPtr<IAutomationReport> InReport)
|
|
{
|
|
if ( InRoot == InReport )
|
|
return true;
|
|
|
|
bool WasExpanded = false;
|
|
|
|
for ( auto ChildReport : InRoot->GetChildReports() )
|
|
{
|
|
auto ShouldExpand = ExpandToTest(ChildReport, InReport);
|
|
TestTable->SetItemExpansion(ChildReport, ShouldExpand);
|
|
|
|
if ( ShouldExpand )
|
|
{
|
|
// Here we could just return true, but we want to collapse all the other reports
|
|
// so we keep going and just remember that we found the test.
|
|
WasExpanded = true;
|
|
}
|
|
}
|
|
|
|
return WasExpanded;
|
|
}
|
|
|
|
#endif
|
|
|
|
|
|
void SAutomationWindow::PopulateReportSearchStrings( const TSharedPtr< IAutomationReport >& Report, OUT TArray< FString >& OutSearchStrings ) const
|
|
{
|
|
if( !Report.IsValid() )
|
|
{
|
|
return;
|
|
}
|
|
|
|
OutSearchStrings.Add( Report->GetDisplayName() );
|
|
OutSearchStrings.Add( Report->GetFullTestPath() );
|
|
}
|
|
|
|
|
|
void SAutomationWindow::OnGetChildren(TSharedPtr<IAutomationReport> InItem, TArray<TSharedPtr<IAutomationReport> >& OutItems)
|
|
{
|
|
OutItems = InItem->GetFilteredChildren();
|
|
}
|
|
|
|
void SAutomationWindow::OnTestExpansionRecursive(TSharedPtr<IAutomationReport> InAutomationReport, bool bInIsItemExpanded)
|
|
{
|
|
if ( InAutomationReport.IsValid() )
|
|
{
|
|
TArray<TSharedPtr<IAutomationReport> >& FilteredChildren = InAutomationReport->GetFilteredChildren();
|
|
|
|
TestTable->SetItemExpansion(InAutomationReport, bInIsItemExpanded);
|
|
|
|
for ( TSharedPtr<IAutomationReport>& Child : FilteredChildren )
|
|
{
|
|
OnTestExpansionRecursive(Child, bInIsItemExpanded);
|
|
}
|
|
}
|
|
}
|
|
|
|
void SAutomationWindow::OnTestSelectionChanged(TSharedPtr<IAutomationReport> Selection, ESelectInfo::Type /*SelectInfo*/)
|
|
{
|
|
TSharedPtr<IAutomationReport> PreviousSelectionLock = PreviousSelection.Pin();
|
|
if ( PreviousSelectionLock.IsValid() )
|
|
{
|
|
PreviousSelectionLock->OnSetResults.Unbind();
|
|
}
|
|
|
|
bHasChildTestSelected = false;
|
|
|
|
UpdateTestLog(Selection);
|
|
|
|
if ( Selection.IsValid() )
|
|
{
|
|
Selection->OnSetResults.BindRaw(this, &SAutomationWindow::UpdateTestLog);
|
|
PreviousSelection = Selection;
|
|
|
|
if ( Selection->GetTotalNumChildren() == 0 )
|
|
{
|
|
bHasChildTestSelected = true;
|
|
}
|
|
}
|
|
}
|
|
|
|
void SAutomationWindow::UpdateTestLog(TSharedPtr<IAutomationReport> Selection)
|
|
{
|
|
//empty the previous log
|
|
LogMessages.Empty();
|
|
|
|
if (Selection.IsValid())
|
|
{
|
|
//accumulate results for each device cluster that supports the test
|
|
int32 NumClusters = AutomationController->GetNumDeviceClusters();
|
|
for (int32 ClusterIndex = 0; ClusterIndex < NumClusters; ++ClusterIndex)
|
|
{
|
|
//no sense displaying device name if only one is available
|
|
if (NumClusters > 1)
|
|
{
|
|
FString DeviceTypeName = AutomationController->GetClusterGroupName(ClusterIndex) + TEXT(" - ") + Selection->GetGameInstanceName(ClusterIndex);
|
|
LogMessages.Add(MakeShareable(new FAutomationOutputMessage(DeviceTypeName, TEXT("Automation.Header"))));
|
|
}
|
|
|
|
const int32 NumOfPasses = Selection->GetNumResults(ClusterIndex);
|
|
for( int32 PassIndex = 0; PassIndex < NumOfPasses; ++PassIndex )
|
|
{
|
|
//get strings out of the report and populate the Log Messages
|
|
FAutomationTestResults TestResults = Selection->GetResults(ClusterIndex,PassIndex);
|
|
|
|
//no sense displaying device name if only one is available
|
|
if (NumOfPasses > 1)
|
|
{
|
|
FString PassHeader = LOCTEXT("TestPassHeader", "Pass:").ToString();
|
|
PassHeader += FString::Printf(TEXT("%i"),PassIndex+1);
|
|
LogMessages.Add(MakeShareable(new FAutomationOutputMessage(PassHeader, TEXT("Automation.Header"))));
|
|
}
|
|
|
|
for (const FAutomationExecutionEntry& Entry : TestResults.GetEntries())
|
|
{
|
|
switch (Entry.Event.Type)
|
|
{
|
|
case EAutomationEventType::Info:
|
|
LogMessages.Add(MakeShareable(new FAutomationOutputMessage(Entry.ToString(), TEXT("Automation.Normal"))));
|
|
break;
|
|
case EAutomationEventType::Warning:
|
|
LogMessages.Add(MakeShareable(new FAutomationOutputMessage(Entry.ToString(), TEXT("Automation.Warning"))));
|
|
break;
|
|
case EAutomationEventType::Error:
|
|
LogMessages.Add(MakeShareable(new FAutomationOutputMessage(Entry.ToString(), TEXT("Automation.Error"))));
|
|
break;
|
|
}
|
|
}
|
|
|
|
if ( ( TestResults.GetWarningTotal() == 0 ) && ( TestResults.GetErrorTotal() == 0 ) && ( Selection->GetState(ClusterIndex, PassIndex) == EAutomationState::Success ) )
|
|
{
|
|
LogMessages.Add(MakeShareable(new FAutomationOutputMessage(LOCTEXT("AutomationTest_SuccessMessage", "Success").ToString(), TEXT("Automation.Normal"))));
|
|
}
|
|
|
|
LogMessages.Add(MakeShareable(new FAutomationOutputMessage(TEXT(""), TEXT("Log.Normal"))));
|
|
}
|
|
}
|
|
}
|
|
|
|
//rebuild UI
|
|
LogListView->RequestListRefresh();
|
|
}
|
|
|
|
|
|
EVisibility SAutomationWindow::GetTestLogVisibility( ) const
|
|
{
|
|
return (GetTestGraphVisibility() == EVisibility::Visible) ? EVisibility::Hidden : EVisibility::Visible;
|
|
}
|
|
|
|
|
|
EVisibility SAutomationWindow::GetTestGraphVisibility( ) const
|
|
{
|
|
//Show the graphical window if we don't have a child test selected and we have results to view
|
|
return (!bHasChildTestSelected && GraphicalResultBox->HasResults()) ? EVisibility::Visible : EVisibility::Hidden;
|
|
}
|
|
|
|
|
|
void SAutomationWindow::HeaderCheckboxStateChange(ECheckBoxState InCheckboxState)
|
|
{
|
|
const bool bState = (InCheckboxState == ECheckBoxState::Checked)? true : false;
|
|
|
|
AutomationController->SetVisibleTestsEnabled(bState);
|
|
}
|
|
|
|
BEGIN_SLATE_FUNCTION_BUILD_OPTIMIZATION
|
|
void SAutomationWindow::RebuildPlatformIcons()
|
|
{
|
|
//empty header UI
|
|
PlatformsHBox->ClearChildren();
|
|
|
|
//for each device type
|
|
int32 NumClusters = AutomationController->GetNumDeviceClusters();
|
|
for (int32 ClusterIndex = 0; ClusterIndex < NumClusters; ++ClusterIndex)
|
|
{
|
|
//find the right platform icon
|
|
FString DeviceTypeName = AutomationController->GetDeviceTypeName(ClusterIndex);
|
|
FName DeviceImageName = PlatformInfo::FindPlatformInfo(FName(*DeviceTypeName))->DataDrivenPlatformInfo->GetIconStyleName(EPlatformIconSize::Normal);
|
|
|
|
const FSlateBrush* ImageToUse = FEditorStyle::GetBrush(DeviceImageName);
|
|
|
|
PlatformsHBox->AddSlot()
|
|
.AutoWidth()
|
|
.MaxWidth(ColumnWidth)
|
|
[
|
|
SNew( SOverlay )
|
|
+ SOverlay::Slot()
|
|
[
|
|
SNew(SBorder)
|
|
.BorderImage( FEditorStyle::GetBrush("ErrorReporting.Box") )
|
|
.HAlign(HAlign_Center)
|
|
.VAlign(VAlign_Center)
|
|
.Padding( FMargin(3,0) )
|
|
.BorderBackgroundColor( FSlateColor( FLinearColor( 1.0f, 0.0f, 1.0f, 0.0f ) ) )
|
|
.ToolTipText( CreateDeviceTooltip( ClusterIndex ) )
|
|
[
|
|
SNew(SImage)
|
|
.DesiredSizeOverride(FVector2D(16.f, 16.f))
|
|
.Image(ImageToUse)
|
|
]
|
|
]
|
|
+ SOverlay::Slot()
|
|
.HAlign(HAlign_Right)
|
|
.VAlign(VAlign_Bottom)
|
|
[
|
|
//Overlay how many devices are in the cluster
|
|
SNew( STextBlock )
|
|
.Text( this, &SAutomationWindow::OnGetNumDevicesInClusterString, ClusterIndex )
|
|
]
|
|
];
|
|
}
|
|
}
|
|
END_SLATE_FUNCTION_BUILD_OPTIMIZATION
|
|
|
|
FText SAutomationWindow::CreateDeviceTooltip(int32 ClusterIndex)
|
|
{
|
|
FTextBuilder ReportBuilder;
|
|
|
|
const int32 NumClusters = AutomationController->GetNumDeviceClusters();
|
|
if( NumClusters > 1 )
|
|
{
|
|
ReportBuilder.AppendLine(LOCTEXT("ToolTipClusterName", "Cluster Name:"));
|
|
ReportBuilder.AppendLine(AutomationController->GetClusterGroupName(ClusterIndex));
|
|
}
|
|
|
|
ReportBuilder.AppendLine(LOCTEXT("ToolTipGameInstances", "Game Instances:"));
|
|
|
|
int32 NumDevices = AutomationController->GetNumDevicesInCluster( ClusterIndex );
|
|
for ( int32 DeviceIndex = 0; DeviceIndex < NumDevices; ++DeviceIndex )
|
|
{
|
|
ReportBuilder.AppendLine(AutomationController->GetGameInstanceName(ClusterIndex, DeviceIndex).LeftPad(2));
|
|
}
|
|
|
|
return ReportBuilder.ToText();
|
|
}
|
|
|
|
|
|
void SAutomationWindow::ClearAutomationUI ()
|
|
{
|
|
// Clear results from the automation controller
|
|
AutomationController->ClearAutomationReports();
|
|
TestTable->RequestTreeRefresh();
|
|
|
|
// Clear the platform icons
|
|
if (PlatformsHBox.IsValid())
|
|
{
|
|
PlatformsHBox->ClearChildren();
|
|
}
|
|
|
|
// Clear the log
|
|
LogMessages.Empty();
|
|
LogListView->RequestListRefresh();
|
|
}
|
|
|
|
|
|
TSharedRef<ITableRow> SAutomationWindow::OnGenerateWidgetForTest( TSharedPtr<IAutomationReport> InItem, const TSharedRef<STableViewBase>& OwnerTable )
|
|
{
|
|
bIsRequestingTests = false;
|
|
return SNew( SAutomationTestItem, OwnerTable )
|
|
.TestStatus( InItem )
|
|
.ColumnWidth( ColumnWidth )
|
|
.HighlightText(this, &SAutomationWindow::HandleAutomationHighlightText)
|
|
.OnCheckedStateChanged(this, &SAutomationWindow::HandleItemCheckBoxCheckedStateChanged);
|
|
}
|
|
|
|
|
|
TSharedRef<ITableRow> SAutomationWindow::OnGenerateWidgetForLog(TSharedPtr<FAutomationOutputMessage> Message, const TSharedRef<STableViewBase>& OwnerTable)
|
|
{
|
|
check(Message.IsValid());
|
|
|
|
// ^((?:[\w]\:|\\)(?:(?:\\[a-z_\-\s0-9\.]+)+)\.(?:cpp|h))\((\d+)\)
|
|
// https://regex101.com/r/vV4cV7/1
|
|
FRegexPattern FileAndLinePattern(TEXT("^((?:[\\w]\\:|\\\\)(?:(?:\\\\[a-z_\\-\\s0-9\\.]+)+)\\.(?:cpp|h))\\((\\d+)\\)"));
|
|
FRegexMatcher FileAndLineRegexMatcher(FileAndLinePattern, Message->Text);
|
|
|
|
TSharedRef<SWidget> SourceLink = SNullWidget::NullWidget;
|
|
|
|
FString MessageString = Message->Text;
|
|
|
|
if ( FileAndLineRegexMatcher.FindNext() )
|
|
{
|
|
FString FileName = FileAndLineRegexMatcher.GetCaptureGroup(1);
|
|
int32 LineNumber = FCString::Atoi(*FileAndLineRegexMatcher.GetCaptureGroup(2));
|
|
|
|
// Remove the hyperlink from the message, since we're splitting it into its own string.
|
|
MessageString.RightChopInline(FileAndLineRegexMatcher.GetMatchEnding(), false);
|
|
|
|
SourceLink = SNew(SHyperlink)
|
|
.Style(FEditorStyle::Get(), "Common.GotoNativeCodeHyperlink")
|
|
.TextStyle(FEditorStyle::Get(), Message->Style)
|
|
.OnNavigate_Lambda([=] { FSlateApplication::Get().GotoLineInSource(FileName, LineNumber); })
|
|
.Text(FText::FromString(FileAndLineRegexMatcher.GetCaptureGroup(0)));
|
|
}
|
|
|
|
return SNew(STableRow<TSharedPtr<FAutomationOutputMessage> >, OwnerTable)
|
|
[
|
|
SNew(SHorizontalBox)
|
|
|
|
+ SHorizontalBox::Slot()
|
|
.AutoWidth()
|
|
.Padding(0)
|
|
[
|
|
SourceLink
|
|
]
|
|
|
|
+ SHorizontalBox::Slot()
|
|
.AutoWidth()
|
|
.Padding(0)
|
|
[
|
|
SNew(STextBlock)
|
|
.TextStyle( FEditorStyle::Get(), Message->Style )
|
|
.Text(FText::FromString(MessageString))
|
|
]
|
|
];
|
|
}
|
|
|
|
|
|
FText SAutomationWindow::OnGetNumEnabledTestsString() const
|
|
{
|
|
int32 NumPasses = AutomationController->GetNumPasses();
|
|
if( NumPasses > 1 )
|
|
{
|
|
return FText::Format(LOCTEXT("NumEnabledTestsFmt", "{0} x{1}"), FText::AsNumber(AutomationController->GetEnabledTestsNum()), FText::AsNumber(NumPasses));
|
|
}
|
|
else
|
|
{
|
|
return FText::AsNumber(AutomationController->GetEnabledTestsNum());
|
|
}
|
|
}
|
|
|
|
|
|
FText SAutomationWindow::OnGetNumDevicesInClusterString(const int32 ClusterIndex) const
|
|
{
|
|
return FText::AsNumber(AutomationController->GetNumDevicesInCluster(ClusterIndex));
|
|
}
|
|
|
|
void SAutomationWindow::OnRefreshTestCallback()
|
|
{
|
|
//if the window hasn't been created yet
|
|
if (!PlatformsHBox.IsValid())
|
|
{
|
|
return;
|
|
}
|
|
|
|
//rebuild the platform header
|
|
RebuildPlatformIcons();
|
|
|
|
//filter the tests that are shown
|
|
AutomationController->SetFilter( AutomationFilters );
|
|
|
|
// Only expand the child nodes if we have a text filter
|
|
bool ExpandChildren = !AutomationTextFilter->GetRawFilterText().IsEmpty();
|
|
|
|
TArray< TSharedPtr< IAutomationReport > >& TestReports = AutomationController->GetReports();
|
|
|
|
for( int32 Index = 0; Index < TestReports.Num(); Index++ )
|
|
{
|
|
ExpandTreeView( TestReports[ Index ], ExpandChildren );
|
|
|
|
// Expand any items that where expanded before refresh tests was pressed.
|
|
if( !ExpandChildren )
|
|
{
|
|
ExpandItemsInList( TestTable, TestReports[Index], SavedExpandedItems );
|
|
}
|
|
}
|
|
|
|
SavedExpandedItems.Empty();
|
|
|
|
//rebuild the UI
|
|
TestTable->RequestTreeRefresh();
|
|
|
|
//update the background style
|
|
UpdateTestListBackgroundStyle();
|
|
}
|
|
|
|
|
|
void SAutomationWindow::OnTestAvailableCallback( EAutomationControllerModuleState::Type InAutomationControllerState )
|
|
{
|
|
AutomationControllerState = InAutomationControllerState;
|
|
|
|
// Only list tests on opening the Window if the asset registry isn't in the middle of loading tests.
|
|
if ( InAutomationControllerState == EAutomationControllerModuleState::Ready && AutomationController->GetReports().Num() == 0 && !bIsRequestingTests)
|
|
{
|
|
#if WITH_EDITOR
|
|
FAssetRegistryModule& AssetRegistryModule = FModuleManager::LoadModuleChecked<FAssetRegistryModule>(TEXT("AssetRegistry"));
|
|
if ( !AssetRegistryModule.Get().IsLoadingAssets() )
|
|
{
|
|
ListTests();
|
|
}
|
|
#else
|
|
ListTests();
|
|
#endif
|
|
}
|
|
}
|
|
|
|
void SAutomationWindow::OnTestsCompleteCallback()
|
|
{
|
|
// Simulate selection again after testing finishes.
|
|
if ( TestTable->GetNumItemsSelected() > 0 )
|
|
{
|
|
OnTestSelectionChanged(TestTable->GetSelectedItems()[0], ESelectInfo::Direct);
|
|
}
|
|
}
|
|
|
|
|
|
void SAutomationWindow::ExpandTreeView( TSharedPtr< IAutomationReport > InReport, const bool ShouldExpand )
|
|
{
|
|
// Expand node if the report is flagged
|
|
TestTable->SetItemExpansion( InReport, ShouldExpand && InReport->ExpandInUI() );
|
|
|
|
// Iterate through the child nodes to see if they should be expanded
|
|
TArray<TSharedPtr< IAutomationReport > > Reports = InReport->GetFilteredChildren();
|
|
|
|
for ( int32 ChildItem = 0; ChildItem < Reports.Num(); ChildItem++ )
|
|
{
|
|
ExpandTreeView( Reports[ ChildItem ], ShouldExpand );
|
|
}
|
|
}
|
|
|
|
//TODO AUTOMATION - remove
|
|
/** Updates list of all the tests */
|
|
void SAutomationWindow::ListTests( )
|
|
{
|
|
// Save Expanded state prior to refresh
|
|
TSet<TSharedPtr<IAutomationReport>> ExpandedItems;
|
|
TestTable->GetExpandedItems(ExpandedItems);
|
|
SavedExpandedItems = SaveExpandedTestNames(ExpandedItems);
|
|
|
|
AutomationController->RequestTests();
|
|
}
|
|
|
|
|
|
//TODO AUTOMATION - remove
|
|
/** Finds available workers */
|
|
void SAutomationWindow::FindWorkers()
|
|
{
|
|
ActiveSession = SessionManager->GetSelectedSession();
|
|
|
|
bool SessionIsValid = ActiveSession.IsValid() && (ActiveSession->GetSessionOwner() == FPlatformProcess::UserName(false));
|
|
|
|
if (SessionIsValid)
|
|
{
|
|
bIsRequestingTests = true;
|
|
|
|
AutomationController->RequestAvailableWorkers(ActiveSession->GetSessionId());
|
|
|
|
RebuildPlatformIcons();
|
|
}
|
|
else
|
|
{
|
|
bIsRequestingTests = false;
|
|
// Clear UI if the session is invalid
|
|
ClearAutomationUI();
|
|
}
|
|
|
|
MenuBar->SetEnabled( SessionIsValid );
|
|
}
|
|
|
|
void SAutomationWindow::HandleSessionManagerInstanceChanged()
|
|
{
|
|
UpdateTestListBackgroundStyle();
|
|
}
|
|
|
|
void SAutomationWindow::UpdateTestListBackgroundStyle()
|
|
{
|
|
TArray<TSharedPtr<ISessionInstanceInfo>> OutInstances;
|
|
|
|
if( ActiveSession.IsValid() )
|
|
{
|
|
ActiveSession->GetInstances(OutInstances);
|
|
}
|
|
|
|
TestBackgroundType = EAutomationTestBackgroundStyle::Unknown;
|
|
|
|
if( OutInstances.Num() > 0 )
|
|
{
|
|
FString FirstInstanceType = OutInstances[0]->GetInstanceType();
|
|
|
|
if( FirstInstanceType.Contains(TEXT("Editor")) )
|
|
{
|
|
TestBackgroundType = EAutomationTestBackgroundStyle::Editor;
|
|
}
|
|
else if( FirstInstanceType.Contains(TEXT("Game")) )
|
|
{
|
|
TestBackgroundType = EAutomationTestBackgroundStyle::Game;
|
|
}
|
|
}
|
|
}
|
|
|
|
|
|
FReply SAutomationWindow::RunTests()
|
|
{
|
|
if( AutomationControllerState == EAutomationControllerModuleState::Running )
|
|
{
|
|
AutomationController->StopTests();
|
|
}
|
|
else
|
|
{
|
|
// Prompt to save current map when running a test.
|
|
#if WITH_EDITOR
|
|
if ( !GIsDemoMode )
|
|
{
|
|
// If there are any unsaved changes to the current level, see if the user wants to save those first.
|
|
const bool bPromptUserToSave = true;
|
|
const bool bSaveMapPackages = true;
|
|
const bool bSaveContentPackages = true;
|
|
if ( FEditorFileUtils::SaveDirtyPackages(bPromptUserToSave, bSaveMapPackages, bSaveContentPackages) == false )
|
|
{
|
|
// something went wrong or the user pressed cancel. Return to the editor so the user doesn't lose their changes
|
|
return FReply::Handled();
|
|
}
|
|
}
|
|
#endif
|
|
|
|
AutomationController->RunTests( ActiveSession->IsStandalone() );
|
|
}
|
|
|
|
LogMessages.Empty();
|
|
LogListView->RequestListRefresh();
|
|
|
|
//Clear old results
|
|
GraphicalResultBox->ClearResults();
|
|
|
|
return FReply::Handled();
|
|
}
|
|
|
|
|
|
/** Filtering */
|
|
void SAutomationWindow::OnFilterTextChanged( const FText& InFilterText )
|
|
{
|
|
AutomationTextFilter->SetRawFilterText( InFilterText );
|
|
AutomationSearchBox->SetError( AutomationTextFilter->GetFilterErrorText() );
|
|
|
|
//update the widget
|
|
OnRefreshTestCallback();
|
|
}
|
|
|
|
|
|
bool SAutomationWindow::IsDeveloperDirectoryIncluded() const
|
|
{
|
|
return AutomationController->IsDeveloperDirectoryIncluded();
|
|
}
|
|
|
|
|
|
void SAutomationWindow::OnToggleDeveloperDirectoryIncluded()
|
|
{
|
|
//Change controller filter
|
|
AutomationController->SetDeveloperDirectoryIncluded(!IsDeveloperDirectoryIncluded());
|
|
// need to call this to request update
|
|
ListTests();
|
|
}
|
|
|
|
bool SAutomationWindow::IsExcludedTestsFilterOn() const
|
|
{
|
|
return AutomationGeneralFilter->ShouldShowOnlyExcludedTests();
|
|
}
|
|
|
|
|
|
void SAutomationWindow::OnToggleExcludedTestsFilter()
|
|
{
|
|
AutomationGeneralFilter->SetShowOnlyExcludedTests(!IsExcludedTestsFilterOn());
|
|
OnRefreshTestCallback();
|
|
}
|
|
|
|
|
|
bool SAutomationWindow::IsSmokeTestFilterOn() const
|
|
{
|
|
return AutomationGeneralFilter->OnlyShowSmokeTests();
|
|
}
|
|
|
|
|
|
void SAutomationWindow::OnToggleSmokeTestFilter()
|
|
{
|
|
AutomationGeneralFilter->SetOnlyShowSmokeTests( !IsSmokeTestFilterOn() );
|
|
OnRefreshTestCallback();
|
|
}
|
|
|
|
|
|
bool SAutomationWindow::IsWarningFilterOn() const
|
|
{
|
|
return AutomationGeneralFilter->ShouldShowWarnings();
|
|
}
|
|
|
|
|
|
void SAutomationWindow::OnToggleWarningFilter()
|
|
{
|
|
AutomationGeneralFilter->SetShowWarnings( !IsWarningFilterOn() );
|
|
OnRefreshTestCallback();
|
|
}
|
|
|
|
|
|
bool SAutomationWindow::IsErrorFilterOn() const
|
|
{
|
|
return AutomationGeneralFilter->ShouldShowErrors();
|
|
}
|
|
|
|
|
|
void SAutomationWindow::OnToggleErrorFilter()
|
|
{
|
|
AutomationGeneralFilter->SetShowErrors( !IsErrorFilterOn() );
|
|
OnRefreshTestCallback();
|
|
}
|
|
|
|
|
|
void SAutomationWindow::OnChangeRepeatCount(int32 InNewValue)
|
|
{
|
|
AutomationController->SetNumPasses(InNewValue);
|
|
}
|
|
|
|
int32 SAutomationWindow::GetRepeatCount() const
|
|
{
|
|
return AutomationController->GetNumPasses();
|
|
}
|
|
|
|
|
|
FString SAutomationWindow::GetSmallIconExtension() const
|
|
{
|
|
FString Brush;
|
|
if (FMultiBoxSettings::UseSmallToolBarIcons.Get())
|
|
{
|
|
Brush += TEXT( ".Small" );
|
|
}
|
|
return Brush;
|
|
}
|
|
|
|
|
|
EVisibility SAutomationWindow::GetLargeToolBarVisibility() const
|
|
{
|
|
return FMultiBoxSettings::UseSmallToolBarIcons.Get() ? EVisibility::Collapsed : EVisibility::Visible;
|
|
}
|
|
|
|
|
|
const FSlateBrush* SAutomationWindow::GetRunAutomationIcon() const
|
|
{
|
|
FString Brush = TEXT( "AutomationWindow" );
|
|
if( AutomationControllerState == EAutomationControllerModuleState::Running )
|
|
{
|
|
Brush += TEXT( ".StopTests" ); // Temporary brush type for stop tests
|
|
}
|
|
else
|
|
{
|
|
Brush += TEXT( ".RunTests" );
|
|
}
|
|
Brush += GetSmallIconExtension();
|
|
return FEditorStyle::GetBrush( *Brush );
|
|
}
|
|
|
|
|
|
FText SAutomationWindow::GetRunAutomationLabel() const
|
|
{
|
|
if( AutomationControllerState == EAutomationControllerModuleState::Running )
|
|
{
|
|
return LOCTEXT( "RunStopTestsLabel", "Stop Tests" );
|
|
}
|
|
else
|
|
{
|
|
return LOCTEXT( "RunStartTestsLabel", "Start Tests" );
|
|
}
|
|
}
|
|
|
|
|
|
FText SAutomationWindow::HandleAutomationHighlightText( ) const
|
|
{
|
|
if ( AutomationSearchBox.IsValid() )
|
|
{
|
|
return AutomationSearchBox->GetText();
|
|
}
|
|
return FText();
|
|
}
|
|
|
|
|
|
EVisibility SAutomationWindow::HandleSelectSessionOverlayVisibility( ) const
|
|
{
|
|
if (SessionManager->GetSelectedInstances().Num() > 0)
|
|
{
|
|
return EVisibility::Hidden;
|
|
}
|
|
|
|
return EVisibility::Visible;
|
|
}
|
|
|
|
|
|
void SAutomationWindow::HandleSessionManagerCanSelectSession( const TSharedPtr<ISessionInfo>& Session, bool& CanSelect )
|
|
{
|
|
if (ActiveSession.IsValid() && AutomationController->CheckTestResultsAvailable())
|
|
{
|
|
EAppReturnType::Type Result = FMessageDialog::Open(EAppMsgType::YesNo, LOCTEXT("ChangeSessionDialog", "Are you sure you want to change sessions?\nAll automation results data will be lost"));
|
|
CanSelect = Result == EAppReturnType::Yes ? true : false;
|
|
}
|
|
}
|
|
|
|
|
|
void SAutomationWindow::HandleSessionManagerSelectionChanged( const TSharedPtr<ISessionInfo>& SelectedSession )
|
|
{
|
|
FindWorkers();
|
|
}
|
|
|
|
|
|
bool SAutomationWindow::IsAutomationControllerIdle() const
|
|
{
|
|
return AutomationControllerState != EAutomationControllerModuleState::Running;
|
|
}
|
|
|
|
|
|
bool SAutomationWindow::IsAutomationRunButtonEnabled() const
|
|
{
|
|
return AutomationControllerState != EAutomationControllerModuleState::Disabled;
|
|
}
|
|
|
|
|
|
void SAutomationWindow::CopyLog( )
|
|
{
|
|
TArray<TSharedPtr<FAutomationOutputMessage> > SelectedItems = LogListView->GetSelectedItems();
|
|
|
|
if (SelectedItems.Num() > 0)
|
|
{
|
|
FString SelectedText;
|
|
|
|
for( int32 Index = 0; Index < SelectedItems.Num(); ++Index )
|
|
{
|
|
SelectedText += SelectedItems[Index]->Text;
|
|
SelectedText += LINE_TERMINATOR;
|
|
}
|
|
|
|
FPlatformApplicationMisc::ClipboardCopy( *SelectedText );
|
|
}
|
|
}
|
|
|
|
|
|
FReply SAutomationWindow::HandleCommandBarCopyLogClicked( )
|
|
{
|
|
CopyLog();
|
|
|
|
return FReply::Handled();
|
|
}
|
|
|
|
|
|
void SAutomationWindow::HandleLogListSelectionChanged( TSharedPtr<FAutomationOutputMessage> InItem, ESelectInfo::Type SelectInfo )
|
|
{
|
|
CommandBar->SetNumLogMessages(LogListView->GetNumItemsSelected());
|
|
}
|
|
|
|
|
|
void SAutomationWindow::ChangeTheSelectionToThisRow(TSharedPtr< IAutomationReport > ThisRow)
|
|
{
|
|
TestTable->SetSelection(ThisRow, ESelectInfo::Direct);
|
|
}
|
|
|
|
bool SAutomationWindow::IsRowSelected(TSharedPtr< IAutomationReport > ThisRow)
|
|
{
|
|
TArray< TSharedPtr<IAutomationReport> >SelectedReport = TestTable->GetSelectedItems();
|
|
|
|
bool ThisRowIsInTheSelectedSet = false;
|
|
|
|
for (int i = 0; i<SelectedReport.Num();++i)
|
|
{
|
|
if (SelectedReport[i] == ThisRow)
|
|
{
|
|
ThisRowIsInTheSelectedSet = true;
|
|
}
|
|
}
|
|
return ThisRowIsInTheSelectedSet;
|
|
}
|
|
|
|
|
|
void SAutomationWindow::SetAllSelectedTestsChecked( bool InChecked )
|
|
{
|
|
TArray< TSharedPtr<IAutomationReport> >SelectedReport = TestTable->GetSelectedItems();
|
|
|
|
for (int i = 0; i<SelectedReport.Num();++i)
|
|
{
|
|
if (SelectedReport[i].IsValid())
|
|
{
|
|
SelectedReport[i]->SetEnabled(InChecked);
|
|
}
|
|
}
|
|
}
|
|
|
|
|
|
bool SAutomationWindow::IsAnySelectedRowEnabled()
|
|
{
|
|
TArray< TSharedPtr<IAutomationReport> >SelectedReport = TestTable->GetSelectedItems();
|
|
|
|
//Do check or uncheck selected rows based on current settings
|
|
bool bFoundCheckedRow = false;
|
|
bool bFoundNotCheckedRow = false;
|
|
bool bRowCheckedValue = true;
|
|
|
|
//Check all the rows if there is a mixture of checked and unchecked then we set all checked, otherwise set to opposite of current values
|
|
|
|
for (int i = 0; i<SelectedReport.Num();++i)
|
|
{
|
|
if (SelectedReport[i].IsValid())
|
|
{
|
|
if (SelectedReport[i]->IsEnabled())
|
|
{
|
|
bFoundCheckedRow = true;
|
|
}
|
|
else
|
|
{
|
|
bFoundNotCheckedRow = true;
|
|
}
|
|
}
|
|
//break when all rows checked or different values found
|
|
if (bFoundCheckedRow && bFoundNotCheckedRow)
|
|
{
|
|
break;
|
|
}
|
|
}
|
|
|
|
//if rows were all checked set to unchecked otherwise we can set to checked
|
|
if (bFoundCheckedRow && !bFoundNotCheckedRow)
|
|
{
|
|
bRowCheckedValue = false;
|
|
}
|
|
|
|
return bRowCheckedValue;
|
|
}
|
|
|
|
|
|
/* SWidget implementation
|
|
*****************************************************************************/
|
|
|
|
FReply SAutomationWindow::OnKeyUp( const FGeometry& InGeometry, const FKeyEvent& InKeyEvent )
|
|
{
|
|
if (InKeyEvent.GetKey() == EKeys::SpaceBar)
|
|
{
|
|
SetAllSelectedTestsChecked(IsAnySelectedRowEnabled());
|
|
return FReply::Handled();
|
|
}
|
|
return FReply::Unhandled();
|
|
}
|
|
|
|
|
|
FReply SAutomationWindow::OnKeyDown( const FGeometry& MyGeometry, const FKeyEvent& InKeyEvent )
|
|
{
|
|
if (InKeyEvent.IsControlDown())
|
|
{
|
|
if (InKeyEvent.GetKey() == EKeys::C)
|
|
{
|
|
CopyLog();
|
|
|
|
return FReply::Handled();
|
|
}
|
|
}
|
|
return FReply::Unhandled();
|
|
}
|
|
|
|
|
|
/* SAutomationWindow callbacks
|
|
*****************************************************************************/
|
|
|
|
void SAutomationWindow::HandleItemCheckBoxCheckedStateChanged( TSharedPtr< IAutomationReport > TestStatus )
|
|
{
|
|
//If multiple rows selected then handle all the rows
|
|
if (AreMultipleRowsSelected())
|
|
{
|
|
//if current row is not in the selected list select that row
|
|
if(IsRowSelected(TestStatus))
|
|
{
|
|
//Just set them all to the opposite of the row just clicked.
|
|
SetAllSelectedTestsChecked(!TestStatus->IsEnabled());
|
|
}
|
|
else
|
|
{
|
|
//Change the selection to this row rather than keep other rows selected unrelated to the ticked/unticked item
|
|
ChangeTheSelectionToThisRow(TestStatus);
|
|
TestStatus->SetEnabled( !TestStatus->IsEnabled() );
|
|
}
|
|
}
|
|
else
|
|
{
|
|
TestStatus->SetEnabled( !TestStatus->IsEnabled() );
|
|
}
|
|
}
|
|
|
|
|
|
bool SAutomationWindow::HandleItemCheckBoxIsEnabled( ) const
|
|
{
|
|
return IsAutomationControllerIdle();
|
|
}
|
|
|
|
|
|
bool SAutomationWindow::HandleMainContentIsEnabled() const
|
|
{
|
|
return (SessionManager->GetSelectedInstances().Num() > 0);
|
|
}
|
|
|
|
#if WITH_EDITOR
|
|
// React to asset registry finishing updating.
|
|
// We only want to do this if there are no tests already listed, otherwise this fires every time you save a map for example.
|
|
void SAutomationWindow::OnAssetRegistryFileLoadProgress(const IAssetRegistry::FFileLoadProgressUpdateData& ProgressUpdateData)
|
|
{
|
|
if ( ProgressUpdateData.NumAssetsProcessedByAssetRegistry == ProgressUpdateData.NumTotalAssets && IsAutomationControllerIdle() && AutomationController->GetReports().Num() == 0 )
|
|
{
|
|
ListTests();
|
|
}
|
|
}
|
|
#endif
|
|
|
|
#undef LOCTEXT_NAMESPACE
|