962 lines
30 KiB
C++
962 lines
30 KiB
C++
// Copyright Epic Games, Inc. All Rights Reserved.
|
|
|
|
#include "SubmitToolWidget.h"
|
|
|
|
#include "ConfirmDialogWidget.h"
|
|
#include "ISettingsModule.h"
|
|
#include "OutputLogModule.h"
|
|
#include "OutputLogSettings.h"
|
|
#include "OutputLogCreationParams.h"
|
|
|
|
#include "View/SubmitToolStyle.h"
|
|
#include "View/SubmitToolCommandHandler.h"
|
|
#include "View/SubmitToolMenu.h"
|
|
#include "View/Widgets/SIntegrationWidget.h"
|
|
|
|
#include "Widgets/Layout/SExpandableArea.h"
|
|
#include "Widgets/Layout/SUniformGridPanel.h"
|
|
#include "Widgets/Layout/SSpacer.h"
|
|
#include "Widgets/Layout/SScrollBox.h"
|
|
#include "Widgets/Layout/SSeparator.h"
|
|
#include "Widgets/Input/SMultiLineEditableTextBox.h"
|
|
#include "Widgets/Views/SListView.h"
|
|
#include "Widgets/Input/SHyperlink.h"
|
|
#include "Widgets/Input/SEditableText.h"
|
|
#include "Widgets/Input/SCheckBox.h"
|
|
#include "Widgets/Images/SThrobber.h"
|
|
#include "Widgets/Docking/SDockTab.h"
|
|
|
|
#include "Models/ModelInterface.h"
|
|
#include "Models/SubmitToolUserPrefs.h"
|
|
#include "TagSectionWidget.h"
|
|
#include "ValidatorsWidget.h"
|
|
|
|
#include "Version/AppVersion.h"
|
|
|
|
#include "Modules/ModuleManager.h"
|
|
#include "Framework/Docking/TabManager.h"
|
|
#include "Framework/Application/SlateApplication.h"
|
|
|
|
#include "CommandLine/CmdLineParameters.h"
|
|
#include "SubmitToolUtils.h"
|
|
#include "Configuration/Configuration.h"
|
|
|
|
#define LOCTEXT_NAMESPACE "SubmitToolWidget"
|
|
|
|
void SubmitToolWidget::OnCLDescriptionUpdated()
|
|
{
|
|
DescriptionBox->Refresh();
|
|
}
|
|
|
|
void SubmitToolWidget::HandleApplicationActivationStateChanged(bool bActive)
|
|
{
|
|
if(ModelInterface == nullptr)
|
|
{
|
|
return;
|
|
}
|
|
if(ModelInterface->IsP4OperationRunning() || ModelInterface->IsBlockingOperationRunning())
|
|
{
|
|
return;
|
|
}
|
|
|
|
if(bActive)
|
|
{
|
|
ModelInterface->CheckForFileEdits();
|
|
ModelInterface->UpdateCLFromP4Async();
|
|
}
|
|
else
|
|
{
|
|
ModelInterface->SendDescriptionToP4();
|
|
}
|
|
}
|
|
|
|
void SubmitToolWidget::Construct(const FArguments& InArgs)
|
|
{
|
|
ParentTab = InArgs._ParentTab.Get();
|
|
ModelInterface = InArgs._ModelInterface;
|
|
|
|
IntegrationWidget = SNew(SIntegrationWidget)
|
|
.ModelInterface(ModelInterface)
|
|
.MainWindow(InArgs._ParentWindow);
|
|
|
|
FSlateApplication::Get().OnApplicationActivationStateChanged().AddRaw(this, &SubmitToolWidget::HandleApplicationActivationStateChanged);
|
|
OnValidatorFinishedHandle = ModelInterface->AddSingleValidatorFinishedCallback(FOnSingleTaskFinished::FDelegate::CreateRaw(this, &SubmitToolWidget::OnSingleValidatorFinished));
|
|
OnValidationUpdateHandle = ModelInterface->AddValidationUpdatedCallback(FOnTaskFinished::FDelegate::CreateRaw(this, &SubmitToolWidget::OnValidationUpdated));
|
|
OnCLDescriptionUpdatedHandle = ModelInterface->GetCLDescriptionUpdatedDelegate().Add(FOnCLDescriptionUpdated::FDelegate::CreateRaw(this, &SubmitToolWidget::OnCLDescriptionUpdated));
|
|
|
|
TSharedPtr<SVerticalBox> Contents;
|
|
ChildSlot
|
|
[
|
|
SNew(SBorder)
|
|
.BorderImage(FAppStyle::GetBrush("ToolPanel.GroupBorder"))
|
|
[
|
|
SAssignNew(Contents, SVerticalBox)
|
|
]
|
|
];
|
|
|
|
/**** Tags ****/
|
|
TSharedRef<STagSectionWidget> TagSection = SNew(STagSectionWidget)
|
|
.ParentWindow(InArgs._ParentWindow)
|
|
.ModelInterface(InArgs._ModelInterface);
|
|
|
|
TSharedRef<SBox> TagSectionBox =
|
|
SNew(SBox)
|
|
.MaxDesiredHeight_Lambda([TagSection]{ return FMath::Min(TagSection->GetDesiredSize().Y, FSubmitToolUserPrefs::Get()->TagSectionSize);})
|
|
[
|
|
TagSection
|
|
];
|
|
|
|
Contents->AddSlot()
|
|
.AutoHeight()
|
|
[
|
|
TagSectionBox
|
|
];
|
|
|
|
TSharedPtr<SBorder> ResizeBorder;
|
|
|
|
Contents->AddSlot()
|
|
.AutoHeight()
|
|
[
|
|
SAssignNew(ResizeBorder, SBorder)
|
|
.OnMouseButtonUp_Lambda([](const FGeometry& Geometry, const FPointerEvent& PointerEvent) { return FReply::Handled().ReleaseMouseCapture(); })
|
|
.OnMouseMove_Lambda([TagSection, this](const FGeometry& Geometry, const FPointerEvent& PointerEvent){
|
|
if (PointerEvent.IsMouseButtonDown(EKeys::LeftMouseButton))
|
|
{
|
|
FSubmitToolUserPrefs::Get()->TagSectionSize = FMath::Clamp(FSubmitToolUserPrefs::Get()->TagSectionSize + PointerEvent.GetCursorDelta().Y, ModelInterface->GetTagsArray().Num() == 0 ? 0 : 35, TagSection->GetDesiredSize().Y);
|
|
return FReply::Handled();
|
|
}
|
|
|
|
return FReply::Unhandled();
|
|
|
|
})
|
|
[
|
|
SNew(SSeparator).Thickness(5)
|
|
.Cursor(EMouseCursor::ResizeUpDown)
|
|
]
|
|
];
|
|
|
|
ResizeBorder->SetOnMouseButtonDown(FPointerEventHandler::CreateLambda([ResizeBorder](const FGeometry& Geometry, const FPointerEvent& PointerEvent) { return FReply::Handled().CaptureMouse(ResizeBorder.ToSharedRef()); }));
|
|
TSharedPtr<SSplitter> Splitter;
|
|
|
|
Contents->AddSlot()
|
|
.FillHeight(1.f)
|
|
[
|
|
SAssignNew(Splitter, SSplitter)
|
|
.Orientation(EOrientation::Orient_Vertical)
|
|
];
|
|
|
|
|
|
TSharedPtr<SHorizontalBox> BottomLine =
|
|
SNew(SHorizontalBox)
|
|
+SHorizontalBox::Slot()
|
|
.HAlign(HAlign_Left)
|
|
[
|
|
SNew(SEditableText)
|
|
.IsReadOnly(true)
|
|
.Text(FText::FromString(FAppVersion::GetVersion()))
|
|
];
|
|
|
|
for(size_t i = 0; i < ModelInterface->GetParameters().GeneralParameters.HelpLinks.Num(); ++i)
|
|
{
|
|
const FDocumentationLink& DocLink = ModelInterface->GetParameters().GeneralParameters.HelpLinks[i];
|
|
SHorizontalBox::FScopedWidgetSlotArguments Slot = BottomLine->AddSlot();
|
|
Slot.AttachWidget(
|
|
SNew(SHyperlink)
|
|
.Style(FSubmitToolStyle::Get(), TEXT("NavigationHyperlink"))
|
|
.Text(FText::FromString(DocLink.Text))
|
|
.ToolTipText(FText::FromString(DocLink.Tooltip))
|
|
.OnNavigate_Lambda([&DocLink]() { FPlatformProcess::LaunchURL(*DocLink.Link, nullptr, nullptr); })
|
|
);
|
|
|
|
if(i != ModelInterface->GetParameters().GeneralParameters.HelpLinks.Num() - 1)
|
|
{
|
|
Slot.HAlign(HAlign_Center);
|
|
}
|
|
else
|
|
{
|
|
Slot.HAlign(HAlign_Right);
|
|
}
|
|
}
|
|
|
|
/**** Version + feedback ****/
|
|
Contents->AddSlot()
|
|
.AutoHeight()
|
|
[
|
|
BottomLine.ToSharedRef()
|
|
];
|
|
|
|
/**** Description + Buttons ****/
|
|
DescriptionBox = SNew(SMultiLineEditableTextBox)
|
|
.Text_Lambda([&ModelInterface = ModelInterface]() { return FText::FromString(ModelInterface->GetCLDescription()); })
|
|
.OnTextChanged_Lambda([&ModelInterface = ModelInterface](const FText& newText) { ModelInterface->SetCLDescription(newText); })
|
|
.OnTextCommitted_Lambda([this](const FText& Text, ETextCommit::Type CommitType) { if(CommitType != ETextCommit::OnEnter) { ModelInterface->ValidateCLDescription(); }})
|
|
.AutoWrapText(true)
|
|
.OnIsTypedCharValid(FOnIsTypedCharValid::CreateLambda([](const TCHAR) { return true; }))
|
|
.IsReadOnly_Lambda([]{ return !FModelInterface::GetInputEnabled();});
|
|
|
|
FString PerforceClientName;
|
|
FCmdLineParameters::Get().GetValue(FSubmitToolCmdLine::P4Client, PerforceClientName);
|
|
|
|
P4SectionSlot = Splitter->AddSlot()
|
|
.Resizable(true)
|
|
.MinSize(150)
|
|
[
|
|
SNew(SBox)
|
|
.WidthOverride(520)
|
|
[
|
|
SNew(SVerticalBox)
|
|
+SVerticalBox::Slot()
|
|
.AutoHeight()
|
|
[
|
|
SNew(SBorder)
|
|
.BorderBackgroundColor(FAppStyle::GetColor("ValidatorStateFail"))
|
|
.Visibility_Lambda([this]() {
|
|
if (FDateTime::Now().GetHour() < ModelInterface->GetParameters().GeneralParameters.EarlySubmitHour24 || FDateTime::Now().GetHour() >= ModelInterface->GetParameters().GeneralParameters.LateSubmitHour24)
|
|
{
|
|
return EVisibility::All;
|
|
}
|
|
else
|
|
{
|
|
return EVisibility::Collapsed;
|
|
}
|
|
})
|
|
[
|
|
SNew(STextBlock)
|
|
.Justification(ETextJustify::Center)
|
|
.TextStyle(FAppStyle::Get(), "BoldTextNormalSize")
|
|
.Text_Lambda([]() { return FText::FromString(FString::Printf(TEXT("**** It's %s local time, be mindful of submitting late and going away, please remain alert and available for a reasonable period of time (2-3 hours) in case your changes cause issues ****"), *FDateTime::Now().ToFormattedString(TEXT("%H:%M")))); })
|
|
]
|
|
]
|
|
+SVerticalBox::Slot()
|
|
.AutoHeight()
|
|
.Padding(FMargin(5))
|
|
[
|
|
SNew(SHorizontalBox)
|
|
+ SHorizontalBox::Slot()
|
|
.HAlign(HAlign_Left)
|
|
.AutoWidth()
|
|
[
|
|
SNew(STextBlock)
|
|
.Font(FAppStyle::Get().GetFontStyle("SmallFontBold"))
|
|
.Text(NSLOCTEXT("SourceControl.SubmitPanel", "ChangeListDesc", "Changelist Description"))
|
|
]
|
|
+ SHorizontalBox::Slot()
|
|
.FillWidth(1.f)
|
|
[
|
|
SNew(SSpacer)
|
|
]
|
|
|
|
// STREAM
|
|
+ SHorizontalBox::Slot()
|
|
.HAlign(HAlign_Right)
|
|
.AutoWidth()
|
|
[
|
|
SNew(STextBlock)
|
|
.Font(FAppStyle::Get().GetFontStyle("SmallFontBold"))
|
|
.Text(NSLOCTEXT("SourceControl.SubmitPanel", "Stream", "Stream"))
|
|
]
|
|
+ SHorizontalBox::Slot()
|
|
.HAlign(HAlign_Right)
|
|
.Padding(5, 0, 0, 0)
|
|
.AutoWidth()
|
|
[
|
|
SNew(STextBlock)
|
|
.Font(FAppStyle::Get().GetFontStyle("SmallFont"))
|
|
.Text_Lambda([this]() { return FText::FromString(ModelInterface->GetCurrentStream()); })
|
|
]
|
|
|
|
// WORKSPACE
|
|
+ SHorizontalBox::Slot()
|
|
.HAlign(HAlign_Right)
|
|
.Padding(15, 0, 0, 0)
|
|
.AutoWidth()
|
|
[
|
|
SNew(STextBlock)
|
|
.Font(FAppStyle::Get().GetFontStyle("SmallFontBold"))
|
|
.Text(NSLOCTEXT("SourceControl.SubmitPanel", "Workspace", "Workspace"))
|
|
]
|
|
+ SHorizontalBox::Slot()
|
|
.HAlign(HAlign_Right)
|
|
.Padding(5, 0, 0, 0)
|
|
.AutoWidth()
|
|
[
|
|
SNew(STextBlock)
|
|
.Font(FAppStyle::Get().GetFontStyle("SmallFont"))
|
|
.Text(FText::FromString(PerforceClientName))
|
|
]
|
|
]
|
|
+SVerticalBox::Slot()
|
|
.FillHeight(.2f)
|
|
.Padding(FMargin(5, 0, 5, 5))
|
|
[
|
|
DescriptionBox.ToSharedRef()
|
|
]
|
|
+ SVerticalBox::Slot()
|
|
.AutoHeight()
|
|
.Padding(FMargin(5, 0, 5, 5))
|
|
[
|
|
BuildButtonRow()
|
|
]
|
|
|
|
]
|
|
].GetSlot();
|
|
|
|
P4SectionSlot->SetSizeValue(FSubmitToolUserPrefs::Get()->P4SectionSize);
|
|
|
|
TSharedPtr<SWidget> LogSection = BuildOutputLogWidget();
|
|
TSharedPtr<SWidget> FilesInCLSection = BuildFilesInCLWidget();
|
|
|
|
// Files & Validators
|
|
ValidatorSectionSlot = Splitter->AddSlot()
|
|
.MinSize(45)
|
|
.SizeRule(SSplitter::ESizeRule::FractionOfParent)
|
|
.Resizable(true)
|
|
[
|
|
SNew(SBox)
|
|
.Padding(0.f,4.f)
|
|
[
|
|
SNew(SScrollBox)
|
|
.Orientation(EOrientation::Orient_Vertical)
|
|
+SScrollBox::Slot()
|
|
.Padding(FMargin(0.f, 2.f))
|
|
.AutoSize()
|
|
[
|
|
FilesInCLSection.ToSharedRef()
|
|
]
|
|
+SScrollBox::Slot()
|
|
.Padding(FMargin(0.f, 2.f))
|
|
.AutoSize()
|
|
[
|
|
SNew(SValidatorsWidget)
|
|
.OnViewLog_Lambda([this](TSharedPtr<const FValidatorBase> validator) { LogTabManager->DrawAttention(ValidatorLogTab.ToSharedRef()); })
|
|
.ModelInterface(ModelInterface)
|
|
]
|
|
]
|
|
].GetSlot();
|
|
|
|
ValidatorSectionSlot->SetSizeValue(FSubmitToolUserPrefs::Get()->ValidatorSectionSize);
|
|
|
|
// Log
|
|
LogSectionSlot = Splitter->AddSlot()
|
|
.MinSize(200)
|
|
.SizeRule(SSplitter::ESizeRule::FractionOfParent)
|
|
.Resizable(true)
|
|
[
|
|
SNew(SVerticalBox)
|
|
+SVerticalBox::Slot()
|
|
.Padding(FMargin(0.f, 4.f))
|
|
.FillHeight(1.f)
|
|
[
|
|
LogSection.ToSharedRef()
|
|
]
|
|
].GetSlot();
|
|
|
|
LogSectionSlot->SetSizeValue(FSubmitToolUserPrefs::Get()->LogSectionSize);
|
|
|
|
}
|
|
|
|
SubmitToolWidget::~SubmitToolWidget()
|
|
{
|
|
if(ModelInterface != nullptr)
|
|
{
|
|
FSubmitToolUserPrefs* UserPrefs = FSubmitToolUserPrefs::Get();
|
|
|
|
UserPrefs->P4SectionSize = P4SectionSlot->GetSizeValue();
|
|
UserPrefs->ValidatorSectionSize = ValidatorSectionSlot->GetSizeValue();
|
|
UserPrefs->LogSectionSize = LogSectionSlot->GetSizeValue();
|
|
|
|
ModelInterface->RemoveValidationFinishedCallback(OnValidatorFinishedHandle);
|
|
ModelInterface->RemoveValidationUpdatedCallback(OnValidationUpdateHandle);
|
|
ModelInterface->GetCLDescriptionUpdatedDelegate().Remove(OnCLDescriptionUpdatedHandle);
|
|
ModelInterface = nullptr;
|
|
}
|
|
}
|
|
|
|
TSharedRef<SHorizontalBox> SubmitToolWidget::BuildButtonRow()
|
|
{
|
|
|
|
ValidateBtn = SNew(SButton)
|
|
.ToolTipText_Raw(this, &SubmitToolWidget::GetValidateButtonTooltip)
|
|
.IsEnabled_Lambda([&ModelInterface = ModelInterface] { return (FModelInterface::GetInputEnabled() && !ModelInterface->GetFilesInCL().IsEmpty()) || ModelInterface->IsP4OperationRunning(); })
|
|
.ButtonStyle(FAppStyle::Get(), "PrimaryButton")
|
|
.OnClicked(this, &SubmitToolWidget::ValidateClicked)
|
|
[
|
|
SNew(STextBlock)
|
|
.MinDesiredWidth(130)
|
|
.Justification(ETextJustify::Center)
|
|
.Text_Raw(this, &SubmitToolWidget::GetValidateButtonText)
|
|
];
|
|
|
|
return SNew(SHorizontalBox)
|
|
#if PLATFORM_WINDOWS
|
|
+ SHorizontalBox::Slot()
|
|
.AutoWidth()
|
|
.VAlign(VAlign_Center)
|
|
[
|
|
SNew(SButton)
|
|
.ButtonStyle(FAppStyle::Get(), "Button")
|
|
.OnClicked(this, &SubmitToolWidget::CopyAllLogsClicked)
|
|
[
|
|
SNew(STextBlock)
|
|
.MinDesiredWidth(130)
|
|
.Justification(ETextJustify::Center)
|
|
.Text(FText::FromString("Copy All Logs"))
|
|
]
|
|
]
|
|
#endif
|
|
+SHorizontalBox::Slot()
|
|
.FillWidth(1.f)
|
|
[
|
|
SNew(SSpacer)
|
|
]
|
|
+ SHorizontalBox::Slot()
|
|
.FillWidth(1.f)
|
|
.HAlign(HAlign_Center)
|
|
.MaxWidth(700)
|
|
.Padding(8, 0)
|
|
.AutoWidth()
|
|
[
|
|
SNew(SThrobber)
|
|
.NumPieces(8)
|
|
.Visibility_Lambda([this]() { return ModelInterface->IsP4OperationRunning() || ModelInterface->IsBlockingOperationRunning() ? EVisibility::Visible : EVisibility::Collapsed; })
|
|
]
|
|
+SHorizontalBox::Slot()
|
|
.FillWidth(1.f)
|
|
.HAlign(HAlign_Right)
|
|
.MaxWidth(700)
|
|
.Padding(4, 0)
|
|
.AutoWidth()
|
|
[
|
|
SNew(SHorizontalBox)
|
|
+SHorizontalBox::Slot()
|
|
.AutoWidth()
|
|
.VAlign(VAlign_Center)
|
|
[
|
|
SNew(SCheckBox)
|
|
.IsChecked_Lambda([this]() { return ModelInterface->bSubmitOnSuccessfulValidation ? ECheckBoxState::Checked : ECheckBoxState::Unchecked; })
|
|
.OnCheckStateChanged_Lambda([this](ECheckBoxState InNewState) { ModelInterface->bSubmitOnSuccessfulValidation = !ModelInterface->bSubmitOnSuccessfulValidation; })
|
|
.IsFocusable(false)
|
|
]
|
|
+SHorizontalBox::Slot()
|
|
.AutoWidth()
|
|
.VAlign(VAlign_Center)
|
|
[
|
|
SNew(SButton)
|
|
.ButtonStyle(FAppStyle::Get(), "InvisibleButton")
|
|
.IsFocusable(false)
|
|
.OnClicked_Lambda([this]() { ModelInterface->bSubmitOnSuccessfulValidation = !ModelInterface->bSubmitOnSuccessfulValidation; return FReply::Handled(); })
|
|
[
|
|
SNew(STextBlock)
|
|
.Justification(ETextJustify::Left)
|
|
.Font(FAppStyle::Get().GetFontStyle("SmallFont"))
|
|
.MinDesiredWidth(60)
|
|
.Text(FText::FromString(TEXT("Submit On Successful Validation")))
|
|
]
|
|
]
|
|
]
|
|
+SHorizontalBox::Slot()
|
|
.FillWidth(1.f)
|
|
.HAlign(HAlign_Right)
|
|
.MaxWidth(700)
|
|
.AutoWidth()
|
|
[
|
|
SNew(SHorizontalBox)
|
|
+SHorizontalBox::Slot()
|
|
.AutoWidth()
|
|
.VAlign(VAlign_Center)
|
|
[
|
|
SNew(SCheckBox)
|
|
.IsChecked_Lambda([this]() { return FSubmitToolUserPrefs::Get()->bOpenJiraOnSubmit ? ECheckBoxState::Checked : ECheckBoxState::Unchecked; })
|
|
.OnCheckStateChanged_Lambda([this](ECheckBoxState InNewState) { FSubmitToolUserPrefs::Get()->bOpenJiraOnSubmit = !FSubmitToolUserPrefs::Get()->bOpenJiraOnSubmit; })
|
|
]
|
|
+SHorizontalBox::Slot()
|
|
.AutoWidth()
|
|
.VAlign(VAlign_Center)
|
|
[
|
|
SNew(SButton)
|
|
.ButtonStyle(FAppStyle::Get(), "InvisibleButton")
|
|
.IsFocusable(false)
|
|
.OnClicked_Lambda([this]() { FSubmitToolUserPrefs::Get()->bOpenJiraOnSubmit = !FSubmitToolUserPrefs::Get()->bOpenJiraOnSubmit; return FReply::Handled(); })
|
|
[
|
|
SNew(STextBlock)
|
|
.Justification(ETextJustify::Left)
|
|
.Font(FAppStyle::Get().GetFontStyle("SmallFont"))
|
|
.MinDesiredWidth(60)
|
|
.Text(FText::FromString(TEXT("Open Ticket on Submit")))
|
|
]
|
|
]
|
|
]
|
|
+SHorizontalBox::Slot()
|
|
.FillWidth(1.f)
|
|
.HAlign(HAlign_Right)
|
|
.MaxWidth(700)
|
|
.AutoWidth()
|
|
[
|
|
SNew(SHorizontalBox)
|
|
+SHorizontalBox::Slot()
|
|
.AutoWidth()
|
|
.VAlign(VAlign_Center)
|
|
[
|
|
SNew(SCheckBox)
|
|
.IsChecked_Lambda([this]() { return FSubmitToolUserPrefs::Get()->bCloseOnSubmit ? ECheckBoxState::Checked : ECheckBoxState::Unchecked; })
|
|
.OnCheckStateChanged_Lambda([this](ECheckBoxState InNewState) { FSubmitToolUserPrefs::Get()->bCloseOnSubmit = !FSubmitToolUserPrefs::Get()->bCloseOnSubmit; })
|
|
]
|
|
+SHorizontalBox::Slot()
|
|
.AutoWidth()
|
|
.VAlign(VAlign_Center)
|
|
[
|
|
SNew(SButton)
|
|
.ButtonStyle(FAppStyle::Get(), "InvisibleButton")
|
|
.IsFocusable(false)
|
|
.OnClicked_Lambda([this]() { FSubmitToolUserPrefs::Get()->bCloseOnSubmit = !FSubmitToolUserPrefs::Get()->bCloseOnSubmit; return FReply::Handled(); })
|
|
[
|
|
SNew(STextBlock)
|
|
.Justification(ETextJustify::Left)
|
|
.Font(FAppStyle::Get().GetFontStyle("SmallFont"))
|
|
.MinDesiredWidth(60)
|
|
.Text(FText::FromString(TEXT("Close on Submit Success")))
|
|
]
|
|
]
|
|
]
|
|
+SHorizontalBox::Slot()
|
|
.FillWidth(1.f)
|
|
.HAlign(HAlign_Right)
|
|
.MaxWidth(700)
|
|
.AutoWidth()
|
|
[
|
|
SNew(SButton)
|
|
.Text(FText::FromString(TEXT("Open Integration Window")))
|
|
.Visibility_Lambda([this] { return ModelInterface->IsIntegrationRequired() && ModelInterface->bIsUserInAllowlist ? EVisibility::Visible : EVisibility::Collapsed; })
|
|
.OnClicked_Lambda([this] { IntegrationWidget->Open(); return FReply::Handled(); })
|
|
.IsEnabled_Lambda([&ModelInterface = ModelInterface]
|
|
{
|
|
if (ModelInterface->IsPreflightRequestInProgress())
|
|
{
|
|
return false;
|
|
}
|
|
|
|
return ModelInterface->IsCLValid();
|
|
})
|
|
[
|
|
SNew(STextBlock)
|
|
.MinDesiredWidth(130)
|
|
.Justification(ETextJustify::Center)
|
|
.Text(FText::FromString(TEXT("Open Integration Window")))
|
|
]
|
|
]
|
|
+ SHorizontalBox::Slot()
|
|
.FillWidth(1.f)
|
|
.HAlign(HAlign_Right)
|
|
.MaxWidth(700)
|
|
.AutoWidth()
|
|
[
|
|
SNew(SUniformGridPanel)
|
|
.SlotPadding(FAppStyle::GetMargin("StandardDialog.SlotPadding"))
|
|
.MinDesiredSlotWidth(FAppStyle::GetFloat("StandardDialog.MinDesiredSlotWidth"))
|
|
+ SUniformGridPanel::Slot(0, 0)
|
|
[
|
|
SNew(SButton)
|
|
.IsEnabled_Lambda([&ModelInterface = ModelInterface]
|
|
{
|
|
if (ModelInterface->IsPreflightRequestInProgress())
|
|
{
|
|
return false;
|
|
}
|
|
|
|
if (ModelInterface->GetState() == ESubmitToolAppState::Finished)
|
|
{
|
|
return true;
|
|
}
|
|
|
|
if (ModelInterface->GetState() == ESubmitToolAppState::WaitingUserInput || (ModelInterface->IsIntegrationRequired() && ModelInterface->bIsUserInAllowlist))
|
|
{
|
|
return ModelInterface->IsCLValid();
|
|
}
|
|
|
|
if(ModelInterface->IsIntegrationRequired())
|
|
{
|
|
return ModelInterface->IsCLValid() || (ModelInterface->GetFilesInCL().IsEmpty() && ModelInterface->HasShelvedFiles() && ModelInterface->HasSubmitToolTag());
|
|
}
|
|
|
|
return false;
|
|
})
|
|
.OnClicked(this, &SubmitToolWidget::SubmitClicked)
|
|
.ButtonStyle(FAppStyle::Get(), "PrimaryButton")
|
|
[
|
|
SNew(STextBlock)
|
|
.MinDesiredWidth(130)
|
|
.Justification(ETextJustify::Center)
|
|
.Text_Raw(this, &SubmitToolWidget::GetMainButtonText)
|
|
]
|
|
]
|
|
+SUniformGridPanel::Slot(1, 0)
|
|
[
|
|
ValidateBtn.ToSharedRef()
|
|
]
|
|
];
|
|
}
|
|
|
|
TSharedRef<SWidget> SubmitToolWidget::BuildOutputLogWidget()
|
|
{
|
|
/*** Output Log Widget ***/
|
|
FOutputLogModule& OutputLogModule = FModuleManager::Get().LoadModuleChecked<FOutputLogModule>("OutputLog");
|
|
|
|
// hide the debug console
|
|
IConsoleVariable* CVar = IConsoleManager::Get().FindConsoleVariable(TEXT("OutputLogModule.HideConsole"));
|
|
if(ensure(CVar))
|
|
{
|
|
CVar->Set(true);
|
|
}
|
|
|
|
// setup OutputLog settings
|
|
UOutputLogSettings* Settings = GetMutableDefault<UOutputLogSettings>();
|
|
if(Settings)
|
|
{
|
|
Settings->CategoryColorizationMode = ELogCategoryColorizationMode::ColorizeWholeLine;
|
|
}
|
|
|
|
ISettingsModule* SettingsModule = FModuleManager::GetModulePtr<ISettingsModule>("Settings");
|
|
if(SettingsModule)
|
|
{
|
|
SettingsModule->RegisterSettings("Editor", "General", "Output Log",
|
|
NSLOCTEXT("OutputLog", "OutputLogSettingsName", "Output Log"),
|
|
NSLOCTEXT("OutputLog", "OutputLogSettingsDescription", "Set up preferences for the Output Log appearance and workflow."),
|
|
Settings
|
|
);
|
|
}
|
|
|
|
LogTabManager = FGlobalTabmanager::Get()->NewTabManager(ParentTab.Pin().ToSharedRef());
|
|
LogTabManager->SetCanDoDragOperation(false);
|
|
|
|
// Menu
|
|
// TODO BC: this is a poor solution to have the menu maintained between the two tabs please revisit
|
|
TSharedRef<FUICommandList> CommandList = MakeShared<FUICommandList>();
|
|
FSubmitToolCommandHandler CommandHandler;
|
|
CommandHandler.AddToCommandList(ModelInterface, CommandList);
|
|
|
|
FMenuBarBuilder MenuBarBuilder = FMenuBarBuilder(CommandList);
|
|
MenuBarBuilder.AddPullDownMenu(LOCTEXT("MainMenu", "Main Menu"), LOCTEXT("OpensMainMenu", "Opens Main Menu"), FNewMenuDelegate::CreateStatic(&FSubmitToolMenu::FillMainMenuEntries));
|
|
#if !UE_BUILD_SHIPPING
|
|
if(!FPaths::IsStaged())
|
|
{
|
|
MenuBarBuilder.AddPullDownMenu(LOCTEXT("Debug Tools", "Debug"), LOCTEXT("OpensDebugMenu", "Opens Debug Menu"), FNewMenuDelegate::CreateStatic(&FSubmitToolMenu::FillDebugMenuEntries));
|
|
}
|
|
#endif
|
|
|
|
const TSharedRef<SWidget> MenuWidget = MenuBarBuilder.MakeWidget();
|
|
LogTabManager->SetAllowWindowMenuBar(true);
|
|
LogTabManager->SetMenuMultiBox(MenuBarBuilder.GetMultiBox(), MenuWidget);
|
|
|
|
const FName SummaryTabId = "SummaryLogTab";
|
|
const FName ValidatorLogTabId = "ValidatorLogTab";
|
|
const FName PresubmitLogTabId = "PresubmitLogTab";
|
|
|
|
// ----------------------------------------------------------------------
|
|
// Summary Log Tab
|
|
// ----------------------------------------------------------------------
|
|
FOutputLogCreationParams SummaryLogCreationParams;
|
|
|
|
SummaryLogCreationParams.AllowAsInitialLogCategory = FAllowLogCategoryCallback::CreateLambda([](const FName LogCategory) {
|
|
return LogCategory == LogSubmitTool.GetCategoryName();
|
|
});
|
|
|
|
SummaryLogCreationParams.DefaultCategorySelection.Emplace(LogSubmitTool.GetCategoryName(), true);
|
|
SummaryLogCreationParams.DefaultCategorySelection.Emplace(LogValidators.GetCategoryName(), false);
|
|
SummaryLogCreationParams.DefaultCategorySelection.Emplace(LogValidatorsResult.GetCategoryName(), true);
|
|
SummaryLogCreationParams.DefaultCategorySelection.Emplace(LogPresubmitResult.GetCategoryName(), true);
|
|
SummaryLogCreationParams.DefaultCategorySelection.Emplace(LogOutputDevice.GetCategoryName(), true);
|
|
SummaryLogCreationParams.DefaultCategorySelection.Emplace(LogSubmitToolP4.GetCategoryName(), true);
|
|
SummaryLogCreationParams.DefaultCategorySelection.Emplace(LogPresubmit.GetCategoryName(), false);
|
|
SummaryLogCreationParams.DefaultCategorySelection.Emplace("SourceControl", true);
|
|
|
|
SummaryLogDockTab = SNew(SDockTab)
|
|
.CanEverClose(false)
|
|
.TabRole(ETabRole::PanelTab)
|
|
.Label(FText::FromString(TEXT("Summary")))
|
|
.OnCanCloseTab(SDockTab::FCanCloseTab::CreateLambda([] { return false; }))
|
|
[
|
|
OutputLogModule.MakeOutputLogWidget(SummaryLogCreationParams)
|
|
];
|
|
|
|
LogTabManager->RegisterTabSpawner(SummaryTabId, FOnSpawnTab::CreateLambda([this](const FSpawnTabArgs& SpawnArgs) { return SummaryLogDockTab.ToSharedRef(); }));
|
|
|
|
// ----------------------------------------------------------------------
|
|
// Validators Log Tab
|
|
// ----------------------------------------------------------------------
|
|
FOutputLogCreationParams ValidatorLogCreationParams;
|
|
ValidatorLogCreationParams.AllowAsInitialLogCategory = FAllowLogCategoryCallback::CreateLambda([](const FName LogCategory) {
|
|
return LogCategory == LogValidators.GetCategoryName();
|
|
});
|
|
|
|
ValidatorLogCreationParams.DefaultCategorySelection.Emplace(LogSubmitTool.GetCategoryName(), false);
|
|
ValidatorLogCreationParams.DefaultCategorySelection.Emplace(LogValidators.GetCategoryName(), true);
|
|
ValidatorLogCreationParams.DefaultCategorySelection.Emplace(LogValidatorsResult.GetCategoryName(), false);
|
|
ValidatorLogCreationParams.DefaultCategorySelection.Emplace(LogPresubmitResult.GetCategoryName(), false);
|
|
ValidatorLogCreationParams.DefaultCategorySelection.Emplace(LogOutputDevice.GetCategoryName(), false);
|
|
ValidatorLogCreationParams.DefaultCategorySelection.Emplace(LogSubmitToolP4.GetCategoryName(), false);
|
|
ValidatorLogCreationParams.DefaultCategorySelection.Emplace(LogPresubmit.GetCategoryName(), false);
|
|
|
|
|
|
ValidatorLogTab = SNew(SDockTab)
|
|
.CanEverClose(false)
|
|
.Label(FText::FromString(TEXT("Validators Log")))
|
|
.TabRole(ETabRole::PanelTab)
|
|
.OnCanCloseTab(SDockTab::FCanCloseTab::CreateLambda([] { return false; }))
|
|
[
|
|
OutputLogModule.MakeOutputLogWidget(ValidatorLogCreationParams)
|
|
];
|
|
|
|
LogTabManager->RegisterTabSpawner(ValidatorLogTabId, FOnSpawnTab::CreateLambda([this](const FSpawnTabArgs& SpawnArgs) { return ValidatorLogTab.ToSharedRef(); }));
|
|
|
|
// ----------------------------------------------------------------------
|
|
// Pre Submit Log Tab
|
|
// ----------------------------------------------------------------------
|
|
FOutputLogCreationParams PresubmitLogCreationParams;
|
|
PresubmitLogCreationParams.AllowAsInitialLogCategory = FAllowLogCategoryCallback::CreateLambda([](const FName LogCategory) {
|
|
return LogCategory == LogPresubmit.GetCategoryName();
|
|
});
|
|
|
|
PresubmitLogCreationParams.DefaultCategorySelection.Emplace(LogPresubmit.GetCategoryName(), true);
|
|
PresubmitLogCreationParams.DefaultCategorySelection.Emplace(LogSubmitTool.GetCategoryName(), false);
|
|
PresubmitLogCreationParams.DefaultCategorySelection.Emplace(LogValidators.GetCategoryName(), false);
|
|
PresubmitLogCreationParams.DefaultCategorySelection.Emplace(LogValidatorsResult.GetCategoryName(), false);
|
|
PresubmitLogCreationParams.DefaultCategorySelection.Emplace(LogPresubmitResult.GetCategoryName(), false);
|
|
PresubmitLogCreationParams.DefaultCategorySelection.Emplace(LogOutputDevice.GetCategoryName(), false);
|
|
PresubmitLogCreationParams.DefaultCategorySelection.Emplace(LogSubmitToolP4.GetCategoryName(), false);
|
|
|
|
PresubmitLogTab = SNew(SDockTab)
|
|
.CanEverClose(false)
|
|
.Label(FText::FromString(TEXT("Presubmit Log")))
|
|
.TabRole(ETabRole::PanelTab)
|
|
.OnCanCloseTab(SDockTab::FCanCloseTab::CreateLambda([] { return false; }))
|
|
[
|
|
OutputLogModule.MakeOutputLogWidget(PresubmitLogCreationParams)
|
|
];
|
|
|
|
LogTabManager->RegisterTabSpawner(PresubmitLogTabId, FOnSpawnTab::CreateLambda([this](const FSpawnTabArgs& SpawnArgs) { return PresubmitLogTab.ToSharedRef(); }));
|
|
|
|
|
|
// ----------------------------------------------------------------------
|
|
// Logs Layout
|
|
// ----------------------------------------------------------------------
|
|
TSharedRef<FTabManager::FLayout> Layout = FTabManager::NewLayout("SubmitToolLogLayout")
|
|
->AddArea
|
|
(
|
|
FTabManager::NewPrimaryArea()
|
|
->SetOrientation(Orient_Horizontal)
|
|
->Split
|
|
(
|
|
FTabManager::NewStack()
|
|
->SetSizeCoefficient(1.0f)
|
|
->SetHideTabWell(true)
|
|
->AddTab(SummaryTabId, ETabState::OpenedTab)
|
|
->AddTab(ValidatorLogTabId, ETabState::OpenedTab)
|
|
->AddTab(PresubmitLogTabId, ETabState::OpenedTab)
|
|
->SetForegroundTab(SummaryTabId)
|
|
)
|
|
);
|
|
|
|
return LogTabManager->RestoreFrom(Layout, ParentTab.Pin()->GetParentWindow()).ToSharedRef();
|
|
}
|
|
|
|
TSharedRef<SExpandableArea> SubmitToolWidget::BuildFilesInCLWidget()
|
|
{
|
|
TSharedPtr<SListView<FSourceControlStateRef>> FileList = SNew(SListView<FSourceControlStateRef>)
|
|
.SelectionMode(ESelectionMode::Single)
|
|
.ListItemsSource(&ModelInterface->GetFilesInCL())
|
|
.OnGenerateRow_Lambda([this](FSourceControlStateRef InItem, const TSharedRef<STableViewBase>& OwnerTable)
|
|
{
|
|
return SNew(STableRow<FSourceControlStateRef>, OwnerTable)
|
|
.Padding(2.0f)
|
|
[
|
|
SNew(SHorizontalBox)
|
|
|
|
+ SHorizontalBox::Slot()
|
|
.MaxWidth(24)
|
|
.HAlign(HAlign_Left)
|
|
[
|
|
SNew(SImage)
|
|
.Image(InItem->GetIcon().GetIcon())
|
|
]
|
|
|
|
+ SHorizontalBox::Slot()
|
|
.AutoWidth()
|
|
.HAlign(HAlign_Left)
|
|
[
|
|
SNew(STextBlock)
|
|
.Text(FText::FromString(InItem->GetFilename()))
|
|
]
|
|
];
|
|
|
|
});
|
|
|
|
ModelInterface->FileRefreshedCallback.AddLambda([FileList]() {FileList->RequestListRefresh(); });
|
|
|
|
return SNew(SExpandableArea)
|
|
.InitiallyCollapsed(!FSubmitToolUserPrefs::Get()->bExpandFilesInCL)
|
|
.OnAreaExpansionChanged_Lambda([](bool bExpanded) { FSubmitToolUserPrefs::Get()->bExpandFilesInCL = bExpanded; })
|
|
.BorderImage(FAppStyle::Get().GetBrush("Brushes.Header"))
|
|
.BodyBorderImage(FAppStyle::Get().GetBrush("Brushes.Recessed"))
|
|
.HeaderPadding(FMargin(4.0f, 2.0f))
|
|
.Padding(1.0f)
|
|
.MaxHeight(200.0f)
|
|
.AllowAnimatedTransition(true)
|
|
.HeaderContent()
|
|
[
|
|
SNew(STextBlock)
|
|
.Text(NSLOCTEXT("SourceControl.SubmitPanel", "ChangeListFiles", "Files in Changelist"))
|
|
]
|
|
.BodyContent()
|
|
[
|
|
SNew(SBox)
|
|
.Padding(2.5)
|
|
[
|
|
FileList.ToSharedRef()
|
|
]
|
|
];
|
|
}
|
|
|
|
FReply SubmitToolWidget::SubmitClicked()
|
|
{
|
|
if(ModelInterface->GetState() == ESubmitToolAppState::Finished)
|
|
{
|
|
ParentTab.Pin()->RequestCloseTab();
|
|
}
|
|
else
|
|
{
|
|
if (ModelInterface->IsIntegrationRequired() && !ModelInterface->bIsUserInAllowlist)
|
|
{
|
|
IntegrationWidget->Open();
|
|
return FReply::Handled();
|
|
}
|
|
|
|
if(ModelInterface->IsCLValid())
|
|
{
|
|
ModelInterface->StartSubmitProcess();
|
|
}
|
|
}
|
|
|
|
return FReply::Handled();
|
|
}
|
|
|
|
FReply SubmitToolWidget::ValidateClicked()
|
|
{
|
|
if(ModelInterface->IsValidationRunning())
|
|
{
|
|
ModelInterface->CancelValidations();
|
|
}
|
|
else
|
|
{
|
|
if(ModelInterface->IsP4OperationRunning())
|
|
{
|
|
ModelInterface->CancelP4Operations();
|
|
}
|
|
else
|
|
{
|
|
ModelInterface->ValidateChangelist();
|
|
}
|
|
}
|
|
|
|
return FReply::Handled();
|
|
}
|
|
|
|
FText SubmitToolWidget::GetMainButtonText() const
|
|
{
|
|
FText FinalText;
|
|
|
|
if(ModelInterface->GetState() == ESubmitToolAppState::Finished)
|
|
{
|
|
FinalText = NSLOCTEXT("SourceControl.SubmitPanel", "CloseButton", "Close");
|
|
}
|
|
else
|
|
{
|
|
FinalText = ModelInterface->IsIntegrationRequired() && !ModelInterface->bIsUserInAllowlist ? NSLOCTEXT("SourceControl.SubmitPanel", "IntegrationButton", "Open Integration Window") : NSLOCTEXT("SourceControl.SubmitPanel", "SubmitButton", "Submit");
|
|
}
|
|
|
|
return FinalText;
|
|
}
|
|
|
|
FText SubmitToolWidget::GetValidateButtonTooltip() const
|
|
{
|
|
|
|
FText FinalText;
|
|
|
|
if(ModelInterface->IsValidationRunning())
|
|
{
|
|
FinalText = NSLOCTEXT("SourceControl.SubmitPanel", "CancelValidateButtonTooltip", "Stops the currently running validations.");
|
|
}
|
|
else
|
|
{
|
|
if(ModelInterface->IsP4OperationRunning())
|
|
{
|
|
FinalText = NSLOCTEXT("SourceControl.SubmitPanel", "CancelP4OpButtonTooltip", "Cancels the currently running P4 Operations.");
|
|
}
|
|
else
|
|
{
|
|
FinalText = NSLOCTEXT("SourceControl.SubmitPanel", "ValidateButtonTooltip", "Run all the validators for this changelist.");
|
|
}
|
|
}
|
|
return FinalText;
|
|
}
|
|
|
|
FText SubmitToolWidget::GetValidateButtonText() const
|
|
{
|
|
FText FinalText;
|
|
|
|
if(ModelInterface->IsValidationRunning())
|
|
{
|
|
FinalText = NSLOCTEXT("SourceControl.SubmitPanel", "CancelValidateButton", "Stop Validations");
|
|
}
|
|
else
|
|
{
|
|
if(ModelInterface->IsP4OperationRunning())
|
|
{
|
|
FinalText = NSLOCTEXT("SourceControl.SubmitPanel", "CancelP4OpButtonText", "Cancel P4 Operations");
|
|
}
|
|
else
|
|
{
|
|
FinalText = NSLOCTEXT("SourceControl.SubmitPanel", "ValidateButtonText", "Validate");
|
|
}
|
|
}
|
|
return FinalText;
|
|
}
|
|
|
|
void SubmitToolWidget::OnSingleValidatorFinished(const FValidatorBase& InValidator)
|
|
{
|
|
if(!InValidator.GetHasPassed())
|
|
{
|
|
ValidatorLogTab->FlashTab();
|
|
}
|
|
}
|
|
|
|
void SubmitToolWidget::OnValidationUpdated(bool bValid)
|
|
{
|
|
if(bValid)
|
|
{
|
|
ValidateBtn->SetButtonStyle(&FAppStyle::Get().GetWidgetStyle<FButtonStyle>("Button"));
|
|
}
|
|
else
|
|
{
|
|
ValidateBtn->SetButtonStyle(&FAppStyle::Get().GetWidgetStyle<FButtonStyle>("PrimaryButton"));
|
|
}
|
|
}
|
|
|
|
#if PLATFORM_WINDOWS
|
|
FReply SubmitToolWidget::CopyAllLogsClicked()
|
|
{
|
|
TArray<FString> Files;
|
|
for (const FString& Path : ModelInterface->GetParameters().CopyLogParameters.LogsToCollect)
|
|
{
|
|
Files.Emplace(FPaths::ConvertRelativePathToFull(FConfiguration::Substitute(Path)));
|
|
}
|
|
|
|
FSubmitToolUtils::CopyDiagnosticFilesToClipboard(Files);
|
|
|
|
UE_LOG(LogSubmitTool,Display, TEXT("Log files have been copied to the clipboard"));
|
|
return FReply::Handled();
|
|
}
|
|
#endif
|
|
|
|
|
|
#undef LOCTEXT_NAMESPACE
|