Files
UnrealEngineUWP/Engine/Source/Editor/SourceControlWindows/Private/SSourceControlSubmit.cpp
paul chipchase 80beaf7cc8 Add a new overload to IVirtualizationSystem::TryVirtualizePackages, which takes additional options (via a bitfield enum) and returns more info about the resulting process. The original version has been drepcated.
#rb Per.Larsson
#jira UE-169626
#rnx
#preflight 639c4112012902cb8db43e13

- This allows us to provide the user with more ways to customize the virtualization and return more detailed info about it if the calling code wishes to log additional info. In both cases we can extend the options and the data returned without changing the API.
- Previously if we virtualized a package that was not checked out in revision control we would warn the user and then skip updating the package file on disk. This means the payloads would be uploaded but the user would be left with no local changes. Since sometimes we know we don't need to check out any package (virtualizing the packages in a change list for example) we don't want to always incur the cost of polling reivision control to see which packages do need checking out. This is why we now allow the caller to request package files be checked out via the new options enum EVirtualizationOptions.
-- If the EVirtualizationOptions::Checkout flag is provided we will poll the revision control status of all package files and then check out those which need it.
-- We still check if packages can be modified and warn the user if they can't, as package files could be locked in other ways.
- Added a new utility function to SourceControlUtilties to make it easier to check out packages. There is similar functionality elsewhere in the code base but the virtualization module is too low level to make use of it.
- Updated existing code that calls ::TryVirtualizePackages and add cases of ''using namespace UE::Virtualization' where required to improve readability.
- The UnrealVirtualizationTool now supports a new cmdline option "-checkout" that can be used when virtualizing packages. This will checkout any package that was actually virtualized so the result can be saved back out to the workspace domain. This means we no longer require the caller to have checked out the packages before running the tool.

[CL 23536832 by paul chipchase in ue5-main branch]
2022-12-16 06:25:07 -05:00

791 lines
23 KiB
C++

// Copyright Epic Games, Inc. All Rights Reserved.
#include "SSourceControlSubmit.h"
#include "ISourceControlOperation.h"
#include "SourceControlOperations.h"
#include "ISourceControlProvider.h"
#include "ISourceControlModule.h"
#include "SourceControlHelpers.h"
#include "SSourceControlCommon.h"
#include "Modules/ModuleManager.h"
#include "Framework/MultiBox/MultiBoxBuilder.h"
#include "Widgets/SWindow.h"
#include "Widgets/Layout/SSpacer.h"
#include "Widgets/Layout/SWrapBox.h"
#include "Widgets/Images/SImage.h"
#include "Widgets/Text/STextBlock.h"
#include "Widgets/Layout/SUniformGridPanel.h"
#include "Widgets/Input/SMultiLineEditableTextBox.h"
#include "Widgets/Input/SButton.h"
#include "Widgets/Notifications/SErrorText.h"
#include "Widgets/Input/SCheckBox.h"
#include "UObject/UObjectHash.h"
#include "Styling/AppStyle.h"
#include "AssetToolsModule.h"
#include "AssetRegistry/AssetRegistryModule.h"
#include "Virtualization/VirtualizationSystem.h"
#include "Logging/MessageLog.h"
#include "RevisionControlStyle/RevisionControlStyle.h"
#if SOURCE_CONTROL_WITH_SLATE
#define LOCTEXT_NAMESPACE "SSourceControlSubmit"
// This is useful for source control that do not support changelist (Git/SVN) or when the submit widget is not created from the changelist window. If a user
// commits/submits this way, then edits the submit description but cancels, the description will be remembered in memory for the next time he tries to submit.
static FText GSavedChangeListDescription;
bool TryToVirtualizeFilesToSubmit(const TArray<FString>& FilesToSubmit, FText& Description, FText& OutFailureMsg)
{
using namespace UE::Virtualization;
{
TArray<FText> PayloadErrors;
TArray<FText> DescriptionTags;
PRAGMA_DISABLE_DEPRECATION_WARNINGS
ISourceControlModule::Get().GetOnPreSubmitFinalize().Broadcast(FilesToSubmit, DescriptionTags, PayloadErrors);
PRAGMA_ENABLE_DEPRECATION_WARNINGS
}
IVirtualizationSystem& System = IVirtualizationSystem::Get();
if (!System.IsEnabled())
{
return true;
}
FVirtualizationResult VirtualizationResults;
EVirtualizationOptions VirtualizationOptions = EVirtualizationOptions::None;
EVirtualizationResult Result = System.TryVirtualizePackages(FilesToSubmit, VirtualizationOptions, VirtualizationResults);
if (Result == EVirtualizationResult::Success)
{
FTextBuilder NewDescription;
NewDescription.AppendLine(Description);
for (const FText& Line : VirtualizationResults.DescriptionTags)
{
NewDescription.AppendLine(Line);
}
Description = NewDescription.ToText();
return true;
}
else if (System.AllowSubmitIfVirtualizationFailed())
{
for (const FText& Error : VirtualizationResults.Errors)
{
FMessageLog("SourceControl").Warning(Error);
}
// Even though the virtualization process had problems we should continue submitting
return true;
}
else
{
for (const FText& Error : VirtualizationResults.Errors)
{
FMessageLog("SourceControl").Error(Error);
}
OutFailureMsg = LOCTEXT("SCC_Virtualization_Failed", "Failed to virtualize the files being submitted!");
return false;
}
}
namespace SSourceControlSubmitWidgetDefs
{
const FName ColumnID_CheckBoxLabel("CheckBox");
const FName ColumnID_IconLabel("Icon");
const FName ColumnID_AssetLabel("Asset");
const FName ColumnID_FileLabel("File");
const float CheckBoxColumnWidth = 23.0f;
const float IconColumnWidth = 21.0f;
}
void SSourceControlSubmitListRow::Construct(const FArguments& InArgs, const TSharedRef<STableViewBase>& InOwnerTableView)
{
SourceControlSubmitWidgetPtr = InArgs._SourceControlSubmitWidget;
Item = InArgs._Item;
SMultiColumnTableRow<TSharedPtr<FFileTreeItem>>::Construct(FSuperRowType::FArguments(), InOwnerTableView);
}
TSharedRef<SWidget> SSourceControlSubmitListRow::GenerateWidgetForColumn(const FName& ColumnName)
{
// Create the widget for this item
TSharedPtr<SSourceControlSubmitWidget> SourceControlSubmitWidget = SourceControlSubmitWidgetPtr.Pin();
if (SourceControlSubmitWidget.IsValid())
{
return SourceControlSubmitWidget->GenerateWidgetForItemAndColumn(Item, ColumnName);
}
// Packages dialog no longer valid; return a valid, null widget.
return SNullWidget::NullWidget;
}
SSourceControlSubmitWidget::~SSourceControlSubmitWidget()
{
// If the user cancel the submit, save the changelist. If the user submitted, ChangeListDescriptionTextCtrl was cleared).
GSavedChangeListDescription = ChangeListDescriptionTextCtrl->GetText();
}
void SSourceControlSubmitWidget::Construct(const FArguments& InArgs)
{
ParentFrame = InArgs._ParentWindow.Get();
SortByColumn = SSourceControlSubmitWidgetDefs::ColumnID_AssetLabel;
SortMode = EColumnSortMode::Ascending;
if (!InArgs._Description.Get().IsEmpty())
{
// If a description is provided, override the last one saved in memory.
GSavedChangeListDescription = InArgs._Description.Get();
}
bAllowSubmit = InArgs._AllowSubmit.Get();
bAllowDiffAgainstDepot = InArgs._AllowDiffAgainstDepot.Get();
const bool bDescriptionIsReadOnly = !InArgs._AllowDescriptionChange.Get();
const bool bAllowUncheckFiles = InArgs._AllowUncheckFiles.Get();
const bool bAllowKeepCheckedOut = InArgs._AllowKeepCheckedOut.Get();
const bool bShowChangelistValidation = !InArgs._ChangeValidationResult.Get().IsEmpty();
const bool bAllowSaveAndClose = InArgs._AllowSaveAndClose.Get();
for (const auto& Item : InArgs._Items.Get())
{
ListViewItems.Add(MakeShareable(new FFileTreeItem(Item)));
}
TSharedRef<SHeaderRow> HeaderRowWidget = SNew(SHeaderRow);
if (bAllowUncheckFiles)
{
HeaderRowWidget->AddColumn(
SHeaderRow::Column(SSourceControlSubmitWidgetDefs::ColumnID_CheckBoxLabel)
[
SNew(SCheckBox)
.IsChecked(this, &SSourceControlSubmitWidget::GetToggleSelectedState)
.OnCheckStateChanged(this, &SSourceControlSubmitWidget::OnToggleSelectedCheckBox)
]
.FixedWidth(SSourceControlSubmitWidgetDefs::CheckBoxColumnWidth)
);
}
HeaderRowWidget->AddColumn(
SHeaderRow::Column(SSourceControlSubmitWidgetDefs::ColumnID_IconLabel)
[
SNew(SSpacer)
]
.SortMode(this, &SSourceControlSubmitWidget::GetColumnSortMode, SSourceControlSubmitWidgetDefs::ColumnID_IconLabel)
.OnSort(this, &SSourceControlSubmitWidget::OnColumnSortModeChanged)
.FixedWidth(SSourceControlSubmitWidgetDefs::IconColumnWidth)
);
HeaderRowWidget->AddColumn(
SHeaderRow::Column(SSourceControlSubmitWidgetDefs::ColumnID_AssetLabel)
.DefaultLabel(LOCTEXT("AssetColumnLabel", "Asset"))
.SortMode(this, &SSourceControlSubmitWidget::GetColumnSortMode, SSourceControlSubmitWidgetDefs::ColumnID_AssetLabel)
.OnSort(this, &SSourceControlSubmitWidget::OnColumnSortModeChanged)
.FillWidth(5.0f)
);
HeaderRowWidget->AddColumn(
SHeaderRow::Column(SSourceControlSubmitWidgetDefs::ColumnID_FileLabel)
.DefaultLabel(LOCTEXT("FileColumnLabel", "File"))
.SortMode(this, &SSourceControlSubmitWidget::GetColumnSortMode, SSourceControlSubmitWidgetDefs::ColumnID_FileLabel)
.OnSort(this, &SSourceControlSubmitWidget::OnColumnSortModeChanged)
.FillWidth(7.0f)
);
TSharedPtr<SVerticalBox> Contents;
ChildSlot
[
SNew(SBorder)
.BorderImage(FAppStyle::GetBrush("ToolPanel.GroupBorder"))
[
SAssignNew(Contents, SVerticalBox)
]
];
// Build contents of dialog
Contents->AddSlot()
.AutoHeight()
.Padding(5)
[
SNew(STextBlock)
.Text(NSLOCTEXT("SourceControl.SubmitPanel", "ChangeListDesc", "Changelist Description"))
];
Contents->AddSlot()
.FillHeight(.5f)
.Padding(FMargin(5, 0, 5, 5))
[
SNew(SBox)
.WidthOverride(520)
[
SAssignNew(ChangeListDescriptionTextCtrl, SMultiLineEditableTextBox)
.SelectAllTextWhenFocused(!bDescriptionIsReadOnly)
.Text(GSavedChangeListDescription)
.AutoWrapText(true)
.IsReadOnly(bDescriptionIsReadOnly)
]
];
Contents->AddSlot()
.Padding(FMargin(5, 0))
[
SNew(SBorder)
[
SAssignNew(ListView, SListView<TSharedPtr<FFileTreeItem>>)
.ItemHeight(20)
.ListItemsSource(&ListViewItems)
.OnGenerateRow(this, &SSourceControlSubmitWidget::OnGenerateRowForList)
.OnContextMenuOpening(this, &SSourceControlSubmitWidget::OnCreateContextMenu)
.OnMouseButtonDoubleClick(this, &SSourceControlSubmitWidget::OnDiffAgainstDepotSelected)
.HeaderRow(HeaderRowWidget)
.SelectionMode(ESelectionMode::Single)
]
];
if (!bDescriptionIsReadOnly)
{
Contents->AddSlot()
.AutoHeight()
.Padding(FMargin(5, 5, 5, 0))
[
SNew( SBorder)
.Visibility(this, &SSourceControlSubmitWidget::IsWarningPanelVisible)
.Padding(5)
[
SNew( SErrorText )
.ErrorText(ChangeListDescriptionTextCtrl->GetText().IsEmpty() ?
NSLOCTEXT("SourceControl.SubmitPanel", "ChangeListDescWarning", "Changelist description is required to submit") :
NSLOCTEXT("SourceControl.SubmitPanel", "Error", "Error!")) // Other errors exist and a better mechanism should be built in to display the right error.
]
];
}
if (bShowChangelistValidation)
{
const FString ChangelistResultText = InArgs._ChangeValidationResult.Get();
const FString ChangelistResultWarningsText = InArgs._ChangeValidationWarnings.Get();
const FString ChangelistResultErrorsText = InArgs._ChangeValidationErrors.Get();
const FName ChangelistSuccessIconName = TEXT("Icons.SuccessWithColor.Large");
const FName ChangelistWarningsIconName = TEXT("Icons.WarningWithColor.Large");
const FName ChangelistErrorsIconName = TEXT("Icons.ErrorWithColor.Large");
const bool bIsSuccess = ChangelistResultWarningsText.IsEmpty() && ChangelistResultErrorsText.IsEmpty();
if (bIsSuccess)
{
Contents->AddSlot()
.AutoHeight()
.Padding(FMargin(5))
[
SNew(SHorizontalBox)
+SHorizontalBox::Slot()
.AutoWidth()
.VAlign(VAlign_Center)
[
SNew(SImage)
.Image(FAppStyle::GetBrush(ChangelistSuccessIconName))
]
+SHorizontalBox::Slot()
[
SNew(SMultiLineEditableTextBox)
.Text(FText::FromString(ChangelistResultText))
.AutoWrapText(true)
.IsReadOnly(true)
]
];
}
else
{
if (!ChangelistResultErrorsText.IsEmpty())
{
Contents->AddSlot()
.Padding(FMargin(5))
[
SNew(SHorizontalBox)
+SHorizontalBox::Slot()
.AutoWidth()
.VAlign(VAlign_Center)
[
SNew(SImage)
.Image(FAppStyle::GetBrush(ChangelistErrorsIconName))
]
+SHorizontalBox::Slot()
[
SNew(SMultiLineEditableTextBox)
.Text(FText::FromString(ChangelistResultErrorsText))
.AutoWrapText(true)
.IsReadOnly(true)
]
];
}
if (!ChangelistResultWarningsText.IsEmpty())
{
Contents->AddSlot()
.Padding(FMargin(5))
[
SNew(SHorizontalBox)
+SHorizontalBox::Slot()
.AutoWidth()
.VAlign(VAlign_Center)
[
SNew(SImage)
.Image(FAppStyle::GetBrush(ChangelistWarningsIconName))
]
+SHorizontalBox::Slot()
[
SNew(SMultiLineEditableTextBox)
.Text(FText::FromString(ChangelistResultWarningsText))
.AutoWrapText(true)
.IsReadOnly(true)
]
];
}
}
}
if (bAllowKeepCheckedOut)
{
Contents->AddSlot()
.AutoHeight()
.Padding(5)
[
SNew(SWrapBox)
.UseAllottedSize(true)
+SWrapBox::Slot()
.Padding(0.0f, 0.0f, 16.0f, 0.0f)
[
SNew(SCheckBox)
.OnCheckStateChanged( this, &SSourceControlSubmitWidget::OnCheckStateChanged_KeepCheckedOut)
.IsChecked( this, &SSourceControlSubmitWidget::GetKeepCheckedOut )
.IsEnabled( this, &SSourceControlSubmitWidget::CanCheckOut )
[
SNew(STextBlock)
.Text(NSLOCTEXT("SourceControl.SubmitPanel", "KeepCheckedOut", "Keep Files Checked Out") )
]
]
];
}
const float AdditionalTopPadding = (bAllowKeepCheckedOut ? 0.0f : 5.0f);
TSharedPtr<SUniformGridPanel> SubmitSaveCancelButtonGrid;
int32 ButtonSlotId = 0;
Contents->AddSlot()
.AutoHeight()
.HAlign(HAlign_Right)
.VAlign(VAlign_Bottom)
.Padding(0.0f, AdditionalTopPadding, 0.0f, 5.0f)
[
SAssignNew(SubmitSaveCancelButtonGrid, SUniformGridPanel)
.SlotPadding(FAppStyle::GetMargin("StandardDialog.SlotPadding"))
.MinDesiredSlotWidth(FAppStyle::GetFloat("StandardDialog.MinDesiredSlotWidth"))
.MinDesiredSlotHeight(FAppStyle::GetFloat("StandardDialog.MinDesiredSlotHeight"))
+SUniformGridPanel::Slot(ButtonSlotId++, 0)
[
SNew(SButton)
.HAlign(HAlign_Center)
.ContentPadding(FAppStyle::GetMargin("StandardDialog.ContentPadding"))
.IsEnabled(this, &SSourceControlSubmitWidget::IsSubmitEnabled)
.Text( NSLOCTEXT("SourceControl.SubmitPanel", "OKButton", "Submit") )
.OnClicked(this, &SSourceControlSubmitWidget::SubmitClicked)
]
];
if (bAllowSaveAndClose)
{
SubmitSaveCancelButtonGrid->AddSlot(ButtonSlotId++, 0)
[
SNew(SButton)
.HAlign(HAlign_Center)
.ContentPadding(FAppStyle::GetMargin("StandardDialog.ContentPadding"))
.Text(NSLOCTEXT("SourceControl.SubmitPanel", "Save", "Save"))
.ToolTipText(NSLOCTEXT("SourceControl.SubmitPanel", "Save_Tooltip", "Save the description and close without submitting."))
.OnClicked(this, &SSourceControlSubmitWidget::SaveAndCloseClicked)
];
}
SubmitSaveCancelButtonGrid->AddSlot(ButtonSlotId++, 0)
[
SNew(SButton)
.HAlign(HAlign_Center)
.ContentPadding(FAppStyle::GetMargin("StandardDialog.ContentPadding"))
.Text( NSLOCTEXT("SourceControl.SubmitPanel", "CancelButton", "Cancel") )
.OnClicked(this, &SSourceControlSubmitWidget::CancelClicked)
];
RequestSort();
DialogResult = ESubmitResults::SUBMIT_CANCELED;
KeepCheckedOut = ECheckBoxState::Unchecked;
ParentFrame.Pin()->SetWidgetToFocusOnActivate(ChangeListDescriptionTextCtrl);
}
/** Corvus: Called to create a context menu when right-clicking on an item */
TSharedPtr<SWidget> SSourceControlSubmitWidget::OnCreateContextMenu()
{
if (SSourceControlSubmitWidget::CanDiffAgainstDepot())
{
FMenuBuilder MenuBuilder(true, NULL);
MenuBuilder.BeginSection("Source Control", NSLOCTEXT("SourceControl.SubmitWindow.Menu", "SourceControlSectionHeader", "Revision Control"));
{
MenuBuilder.AddMenuEntry(
NSLOCTEXT("SourceControl.SubmitWindow.Menu", "DiffAgainstDepot", "Diff Against Depot"),
NSLOCTEXT("SourceControl.SubmitWindow.Menu", "DiffAgainstDepotTooltip", "Look at differences between your version of the asset and that in revision control."),
FSlateIcon(FAppStyle::GetAppStyleSetName(), "SourceControl.Actions.Diff"),
FUIAction(
FExecuteAction::CreateSP(this, &SSourceControlSubmitWidget::OnDiffAgainstDepot),
FCanExecuteAction::CreateSP(this, &SSourceControlSubmitWidget::CanDiffAgainstDepot)
)
);
}
MenuBuilder.EndSection();
return MenuBuilder.MakeWidget();
}
else
{
return nullptr;
}
}
bool SSourceControlSubmitWidget::CanDiffAgainstDepot() const
{
bool bCanDiff = false;
if (bAllowDiffAgainstDepot)
{
const auto& SelectedItems = ListView->GetSelectedItems();
if (SelectedItems.Num() == 1)
{
bCanDiff = SelectedItems[0]->CanDiff();
}
}
return bCanDiff;
}
void SSourceControlSubmitWidget::OnDiffAgainstDepot()
{
const auto& SelectedItems = ListView->GetSelectedItems();
if (SelectedItems.Num() == 1)
{
OnDiffAgainstDepotSelected(SelectedItems[0]);
}
}
void SSourceControlSubmitWidget::OnDiffAgainstDepotSelected(TSharedPtr<FFileTreeItem> InSelectedItem)
{
if (bAllowDiffAgainstDepot)
{
FString PackageName;
if (FPackageName::TryConvertFilenameToLongPackageName(InSelectedItem->GetFileName().ToString(), PackageName))
{
TArray<FAssetData> Assets;
FAssetRegistryModule& AssetRegistryModule = FModuleManager::LoadModuleChecked<FAssetRegistryModule>(TEXT("AssetRegistry"));
AssetRegistryModule.Get().GetAssetsByPackageName(*PackageName, Assets);
if (Assets.Num() == 1)
{
const FAssetData& AssetData = Assets[0];
UObject* CurrentObject = AssetData.GetAsset();
if (CurrentObject)
{
const FString AssetName = AssetData.AssetName.ToString();
FAssetToolsModule& AssetToolsModule = FModuleManager::GetModuleChecked<FAssetToolsModule>("AssetTools");
AssetToolsModule.Get().DiffAgainstDepot(CurrentObject, PackageName, AssetName);
}
}
}
}
}
FReply SSourceControlSubmitWidget::OnKeyDown( const FGeometry& MyGeometry, const FKeyEvent& InKeyEvent )
{
// Pressing escape returns as if the user clicked cancel
if (InKeyEvent.GetKey() == EKeys::Escape)
{
return CancelClicked();
}
return FReply::Unhandled();
}
TSharedRef<SWidget> SSourceControlSubmitWidget::GenerateWidgetForItemAndColumn(TSharedPtr<FFileTreeItem> Item, const FName ColumnID) const
{
check(Item.IsValid());
const FMargin RowPadding(3, 0, 0, 0);
TSharedPtr<SWidget> ItemContentWidget;
if (ColumnID == SSourceControlSubmitWidgetDefs::ColumnID_CheckBoxLabel)
{
ItemContentWidget = SNew(SHorizontalBox)
+ SHorizontalBox::Slot()
.Padding(RowPadding)
[
SNew(SCheckBox)
.IsChecked(Item.Get(), &FFileTreeItem::GetCheckBoxState)
.OnCheckStateChanged(Item.Get(), &FFileTreeItem::SetCheckBoxState)
];
}
else if (ColumnID == SSourceControlSubmitWidgetDefs::ColumnID_IconLabel)
{
ItemContentWidget = SNew(SHorizontalBox)
+ SHorizontalBox::Slot()
.HAlign(HAlign_Center)
.VAlign(VAlign_Center)
[
SNew(SImage)
.Image(FRevisionControlStyleManager::Get().GetBrush(Item->GetIconName()))
.ToolTipText(Item->GetIconTooltip())
];
}
else if (ColumnID == SSourceControlSubmitWidgetDefs::ColumnID_AssetLabel)
{
ItemContentWidget = SNew(SHorizontalBox)
+ SHorizontalBox::Slot()
.Padding(RowPadding)
[
SNew(STextBlock)
.Text(Item->GetAssetName())
];
}
else if (ColumnID == SSourceControlSubmitWidgetDefs::ColumnID_FileLabel)
{
ItemContentWidget = SNew(SHorizontalBox)
+ SHorizontalBox::Slot()
.Padding(RowPadding)
[
SNew(STextBlock)
.Text(Item->GetPackageName())
.ToolTipText(Item->GetFileName())
];
}
return ItemContentWidget.ToSharedRef();
}
ECheckBoxState SSourceControlSubmitWidget::GetToggleSelectedState() const
{
// Default to a Checked state
ECheckBoxState PendingState = ECheckBoxState::Checked;
// Iterate through the list of selected items
for (const TSharedPtr<FFileTreeItem>& Item : ListViewItems)
{
if (Item->GetCheckBoxState() == ECheckBoxState::Unchecked)
{
// If any item in the list is Unchecked, then represent the entire set of highlighted items as Unchecked,
// so that the first (user) toggle of ToggleSelectedCheckBox consistently Checks all items
PendingState = ECheckBoxState::Unchecked;
break;
}
}
return PendingState;
}
void SSourceControlSubmitWidget::OnToggleSelectedCheckBox(ECheckBoxState InNewState)
{
for (const TSharedPtr<FFileTreeItem>& Item : ListViewItems)
{
Item->SetCheckBoxState(InNewState);
}
ListView->RequestListRefresh();
}
void SSourceControlSubmitWidget::FillChangeListDescription(FChangeListDescription& OutDesc)
{
OutDesc.Description = ChangeListDescriptionTextCtrl->GetText();
OutDesc.FilesForAdd.Empty();
OutDesc.FilesForSubmit.Empty();
for (const TSharedPtr<FFileTreeItem>& Item : ListViewItems)
{
if (Item->GetCheckBoxState() == ECheckBoxState::Checked)
{
if (Item->CanCheckIn())
{
OutDesc.FilesForSubmit.Add(Item->GetFileName().ToString());
}
else if (Item->NeedsAdding())
{
OutDesc.FilesForAdd.Add(Item->GetFileName().ToString());
}
}
}
}
bool SSourceControlSubmitWidget::WantToKeepCheckedOut()
{
return KeepCheckedOut == ECheckBoxState::Checked ? true : false;
}
void SSourceControlSubmitWidget::ClearChangeListDescription()
{
ChangeListDescriptionTextCtrl->SetText(FText());
}
FReply SSourceControlSubmitWidget::SubmitClicked()
{
DialogResult = ESubmitResults::SUBMIT_ACCEPTED;
ParentFrame.Pin()->RequestDestroyWindow();
return FReply::Handled();
}
FReply SSourceControlSubmitWidget::CancelClicked()
{
DialogResult = ESubmitResults::SUBMIT_CANCELED;
ParentFrame.Pin()->RequestDestroyWindow();
return FReply::Handled();
}
FReply SSourceControlSubmitWidget::SaveAndCloseClicked()
{
DialogResult = ESubmitResults::SUBMIT_SAVED;
ParentFrame.Pin()->RequestDestroyWindow();
return FReply::Handled();
}
bool SSourceControlSubmitWidget::IsSubmitEnabled() const
{
return bAllowSubmit && !ChangeListDescriptionTextCtrl->GetText().IsEmpty();
}
EVisibility SSourceControlSubmitWidget::IsWarningPanelVisible() const
{
return IsSubmitEnabled() ? EVisibility::Collapsed : EVisibility::Visible;
}
void SSourceControlSubmitWidget::OnCheckStateChanged_KeepCheckedOut(ECheckBoxState InState)
{
KeepCheckedOut = InState;
}
ECheckBoxState SSourceControlSubmitWidget::GetKeepCheckedOut() const
{
return KeepCheckedOut;
}
bool SSourceControlSubmitWidget::CanCheckOut() const
{
const ISourceControlProvider& SourceControlProvider = ISourceControlModule::Get().GetProvider();
return SourceControlProvider.UsesCheckout();
}
TSharedRef<ITableRow> SSourceControlSubmitWidget::OnGenerateRowForList(TSharedPtr<FFileTreeItem> SubmitItem, const TSharedRef<STableViewBase>& OwnerTable)
{
TSharedRef<ITableRow> Row =
SNew(SSourceControlSubmitListRow, OwnerTable)
.SourceControlSubmitWidget(SharedThis(this))
.Item(SubmitItem)
.IsEnabled(SubmitItem->IsEnabled());
return Row;
}
EColumnSortMode::Type SSourceControlSubmitWidget::GetColumnSortMode(const FName ColumnId) const
{
if (SortByColumn != ColumnId)
{
return EColumnSortMode::None;
}
return SortMode;
}
void SSourceControlSubmitWidget::OnColumnSortModeChanged(const EColumnSortPriority::Type SortPriority, const FName& ColumnId, const EColumnSortMode::Type InSortMode)
{
SortByColumn = ColumnId;
SortMode = InSortMode;
RequestSort();
}
void SSourceControlSubmitWidget::RequestSort()
{
// Sort the list of root items
SortTree();
ListView->RequestListRefresh();
}
void SSourceControlSubmitWidget::SortTree()
{
if (SortByColumn == SSourceControlSubmitWidgetDefs::ColumnID_AssetLabel)
{
if (SortMode == EColumnSortMode::Ascending)
{
ListViewItems.Sort([](const TSharedPtr<FFileTreeItem>& A, const TSharedPtr<FFileTreeItem>& B) {
return A->GetAssetName().ToString() < B->GetAssetName().ToString(); });
}
else if (SortMode == EColumnSortMode::Descending)
{
ListViewItems.Sort([](const TSharedPtr<FFileTreeItem>& A, const TSharedPtr<FFileTreeItem>& B) {
return A->GetAssetName().ToString() >= B->GetAssetName().ToString(); });
}
}
else if (SortByColumn == SSourceControlSubmitWidgetDefs::ColumnID_FileLabel)
{
if (SortMode == EColumnSortMode::Ascending)
{
ListViewItems.Sort([](const TSharedPtr<FFileTreeItem>& A, const TSharedPtr<FFileTreeItem>& B) {
return A->GetPackageName().ToString() < B->GetPackageName().ToString(); });
}
else if (SortMode == EColumnSortMode::Descending)
{
ListViewItems.Sort([](const TSharedPtr<FFileTreeItem>& A, const TSharedPtr<FFileTreeItem>& B) {
return A->GetPackageName().ToString() >= B->GetPackageName().ToString(); });
}
}
else if (SortByColumn == SSourceControlSubmitWidgetDefs::ColumnID_IconLabel)
{
if (SortMode == EColumnSortMode::Ascending)
{
ListViewItems.Sort([](const TSharedPtr<FFileTreeItem>& A, const TSharedPtr<FFileTreeItem>& B) {
return A->GetIconName().ToString() < B->GetIconName().ToString(); });
}
else if (SortMode == EColumnSortMode::Descending)
{
ListViewItems.Sort([](const TSharedPtr<FFileTreeItem>& A, const TSharedPtr<FFileTreeItem>& B) {
return A->GetIconName().ToString() >= B->GetIconName().ToString(); });
}
}
}
#undef LOCTEXT_NAMESPACE
#endif // SOURCE_CONTROL_WITH_SLATE