You've already forked UnrealEngineUWP
mirror of
https://github.com/izzy2lost/UnrealEngineUWP.git
synced 2026-03-26 18:15:20 -07:00
Added a hint flag to prevent us from needing to perform whole-repo updates for every multi-file status update (such as those in the content browser). This also keeps the performance improvements we get form querying the workign copy root when 'Submit to source control...' is clicked. Also added a temp fix for a crash when initializing the file list in the submit dialog where plugin content would not resolve package names correctly. Right now we just display the filename. A proper fix is hopefully incoming from Rob M (listed as UE-11493) which measn we can revert back to using package names. From this UDN: https://udn.unrealengine.com/questions/238672/potential-threading-issue-using-subversion-in-edit.html UE-11466 - SVN status can take a very long time in certain circumstances, and possibly crash [CL 2473604 by Thomas Sarkanen in Main branch]
745 lines
23 KiB
C++
745 lines
23 KiB
C++
// Copyright 1998-2015 Epic Games, Inc. All Rights Reserved.
|
|
|
|
#include "SourceControlWindowsPCH.h"
|
|
#include "AssetToolsModule.h"
|
|
#include "MessageLog.h"
|
|
#include "SNotificationList.h"
|
|
#include "NotificationManager.h"
|
|
#include "FileHelpers.h"
|
|
#include "SSourceControlSubmit.h"
|
|
|
|
|
|
IMPLEMENT_MODULE( FDefaultModuleImpl, SourceControlWindows );
|
|
|
|
#if SOURCE_CONTROL_WITH_SLATE
|
|
|
|
#define LOCTEXT_NAMESPACE "SSourceControlSubmit"
|
|
|
|
|
|
namespace SSourceControlSubmitWidgetDefs
|
|
{
|
|
const FName ColumnID_CheckBoxLabel("CheckBox");
|
|
const FName ColumnID_IconLabel("Icon");
|
|
const FName ColumnID_FileLabel("File");
|
|
|
|
const float CheckBoxColumnWidth = 23.0f;
|
|
const float IconColumnWidth = 21.0f;
|
|
}
|
|
|
|
|
|
FSubmitItem::FSubmitItem(const FSourceControlStateRef& InItem)
|
|
: Item(InItem)
|
|
{
|
|
CheckBoxState = ECheckBoxState::Checked;
|
|
DisplayName = FText::FromString(Item->GetFilename());
|
|
}
|
|
|
|
|
|
void SSourceControlSubmitListRow::Construct(const FArguments& InArgs, const TSharedRef<STableViewBase>& InOwnerTableView)
|
|
{
|
|
SourceControlSubmitWidgetPtr = InArgs._SourceControlSubmitWidget;
|
|
Item = InArgs._Item;
|
|
|
|
SMultiColumnTableRow<TSharedPtr<FSubmitItem>>::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;
|
|
}
|
|
|
|
|
|
void SSourceControlSubmitWidget::Construct(const FArguments& InArgs)
|
|
{
|
|
ParentFrame = InArgs._ParentWindow.Get();
|
|
SortByColumn = SSourceControlSubmitWidgetDefs::ColumnID_FileLabel;
|
|
SortMode = EColumnSortMode::Ascending;
|
|
|
|
for (const auto& Item : InArgs._Items.Get())
|
|
{
|
|
ListViewItems.Add(MakeShareable(new FSubmitItem(Item)));
|
|
}
|
|
|
|
TSharedRef<SHeaderRow> HeaderRowWidget = SNew(SHeaderRow);
|
|
|
|
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_FileLabel)
|
|
.DefaultLabel(LOCTEXT("FileColumnLabel", "File"))
|
|
.SortMode(this, &SSourceControlSubmitWidget::GetColumnSortMode, SSourceControlSubmitWidgetDefs::ColumnID_FileLabel)
|
|
.OnSort(this, &SSourceControlSubmitWidget::OnColumnSortModeChanged)
|
|
.FillWidth(7.0f)
|
|
);
|
|
|
|
ChildSlot
|
|
[
|
|
SNew(SBorder)
|
|
.BorderImage(FEditorStyle::GetBrush("ToolPanel.GroupBorder"))
|
|
[
|
|
SNew(SVerticalBox)
|
|
+SVerticalBox::Slot()
|
|
.AutoHeight()
|
|
.Padding(5)
|
|
[
|
|
SNew( STextBlock )
|
|
.Text( NSLOCTEXT("SourceControl.SubmitPanel", "ChangeListDesc", "Changelist Description") )
|
|
]
|
|
+SVerticalBox::Slot()
|
|
.AutoHeight()
|
|
.Padding(FMargin(5, 0, 5, 5))
|
|
[
|
|
SNew(SBox)
|
|
.WidthOverride(520)
|
|
[
|
|
SAssignNew( ChangeListDescriptionTextCtrl, SMultiLineEditableTextBox )
|
|
.SelectAllTextWhenFocused( true )
|
|
.AutoWrapText( true )
|
|
]
|
|
]
|
|
+SVerticalBox::Slot()
|
|
.Padding(FMargin(5, 0))
|
|
[
|
|
SNew(SBorder)
|
|
[
|
|
SAssignNew(ListView, SListView<TSharedPtr<FSubmitItem>>)
|
|
.ItemHeight(20)
|
|
.ListItemsSource(&ListViewItems)
|
|
.OnGenerateRow(this, &SSourceControlSubmitWidget::OnGenerateRowForList)
|
|
.HeaderRow(HeaderRowWidget)
|
|
.SelectionMode(ESelectionMode::None)
|
|
]
|
|
]
|
|
+SVerticalBox::Slot()
|
|
.AutoHeight()
|
|
.Padding(FMargin(5, 5, 5, 0))
|
|
[
|
|
SNew( SBorder)
|
|
.Visibility(this, &SSourceControlSubmitWidget::IsWarningPanelVisible)
|
|
.Padding(5)
|
|
[
|
|
SNew( SErrorText )
|
|
.ErrorText( NSLOCTEXT("SourceControl.SubmitPanel", "ChangeListDescWarning", "Changelist description is required to submit") )
|
|
]
|
|
]
|
|
+SVerticalBox::Slot()
|
|
.AutoHeight()
|
|
.Padding(5)
|
|
[
|
|
SNew(SWrapBox)
|
|
.UseAllottedWidth(true)
|
|
+SWrapBox::Slot()
|
|
.Padding(0.0f, 0.0f, 16.0f, 0.0f)
|
|
[
|
|
SNew(SCheckBox)
|
|
.OnCheckStateChanged( this, &SSourceControlSubmitWidget::OnCheckStateChanged_KeepCheckedOut)
|
|
.IsChecked( this, &SSourceControlSubmitWidget::GetKeepCheckedOut )
|
|
[
|
|
SNew(STextBlock)
|
|
.Text(NSLOCTEXT("SourceControl.SubmitPanel", "KeepCheckedOut", "Keep Files Checked Out") )
|
|
]
|
|
]
|
|
]
|
|
+SVerticalBox::Slot()
|
|
.AutoHeight()
|
|
.HAlign(HAlign_Right)
|
|
.VAlign(VAlign_Bottom)
|
|
.Padding(0.0f,0.0f,0.0f,5.0f)
|
|
[
|
|
SNew(SUniformGridPanel)
|
|
.SlotPadding(FEditorStyle::GetMargin("StandardDialog.SlotPadding"))
|
|
.MinDesiredSlotWidth(FEditorStyle::GetFloat("StandardDialog.MinDesiredSlotWidth"))
|
|
.MinDesiredSlotHeight(FEditorStyle::GetFloat("StandardDialog.MinDesiredSlotHeight"))
|
|
+SUniformGridPanel::Slot(0,0)
|
|
[
|
|
SNew(SButton)
|
|
.HAlign(HAlign_Center)
|
|
.ContentPadding(FEditorStyle::GetMargin("StandardDialog.ContentPadding"))
|
|
.IsEnabled(this, &SSourceControlSubmitWidget::IsOKEnabled)
|
|
.Text( NSLOCTEXT("SourceControl.SubmitPanel", "OKButton", "OK") )
|
|
.OnClicked(this, &SSourceControlSubmitWidget::OKClicked)
|
|
]
|
|
+SUniformGridPanel::Slot(1,0)
|
|
[
|
|
SNew(SButton)
|
|
.HAlign(HAlign_Center)
|
|
.ContentPadding(FEditorStyle::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);
|
|
}
|
|
|
|
|
|
TSharedRef<SWidget> SSourceControlSubmitWidget::GenerateWidgetForItemAndColumn(TSharedPtr<FSubmitItem> 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(), &FSubmitItem::GetCheckBoxState)
|
|
.OnCheckStateChanged(Item.Get(), &FSubmitItem::SetCheckBoxState)
|
|
];
|
|
}
|
|
else if (ColumnID == SSourceControlSubmitWidgetDefs::ColumnID_IconLabel)
|
|
{
|
|
ItemContentWidget = SNew(SHorizontalBox)
|
|
+ SHorizontalBox::Slot()
|
|
.HAlign(HAlign_Center)
|
|
.VAlign(VAlign_Center)
|
|
[
|
|
SNew(SImage)
|
|
.Image(FEditorStyle::GetBrush(Item->GetIconName()))
|
|
.ToolTipText(Item->GetIconTooltip())
|
|
];
|
|
}
|
|
else if (ColumnID == SSourceControlSubmitWidgetDefs::ColumnID_FileLabel)
|
|
{
|
|
ItemContentWidget = SNew(SHorizontalBox)
|
|
+ SHorizontalBox::Slot()
|
|
.Padding(RowPadding)
|
|
[
|
|
SNew(STextBlock)
|
|
.Text(Item->GetDisplayName())
|
|
];
|
|
}
|
|
|
|
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 auto& 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 auto& Item : ListViewItems)
|
|
{
|
|
Item->SetCheckBoxState(InNewState);
|
|
}
|
|
|
|
ListView->RequestListRefresh();
|
|
}
|
|
|
|
|
|
void SSourceControlSubmitWidget::FillChangeListDescription(FChangeListDescription& OutDesc)
|
|
{
|
|
OutDesc.Description = ChangeListDescriptionTextCtrl->GetText();
|
|
OutDesc.FilesForAdd.Empty();
|
|
OutDesc.FilesForSubmit.Empty();
|
|
|
|
for (const auto& Item : ListViewItems)
|
|
{
|
|
if (Item->GetCheckBoxState() == ECheckBoxState::Checked)
|
|
{
|
|
if (Item->CanCheckIn())
|
|
{
|
|
OutDesc.FilesForSubmit.Add(Item->GetFilename());
|
|
}
|
|
else if (Item->NeedsAdding())
|
|
{
|
|
OutDesc.FilesForAdd.Add(Item->GetFilename());
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
|
|
bool SSourceControlSubmitWidget::WantToKeepCheckedOut()
|
|
{
|
|
return KeepCheckedOut == ECheckBoxState::Checked ? true : false;
|
|
}
|
|
|
|
|
|
FReply SSourceControlSubmitWidget::OKClicked()
|
|
{
|
|
DialogResult = ESubmitResults::SUBMIT_ACCEPTED;
|
|
ParentFrame.Pin()->RequestDestroyWindow();
|
|
|
|
return FReply::Handled();
|
|
}
|
|
|
|
|
|
FReply SSourceControlSubmitWidget::CancelClicked()
|
|
{
|
|
DialogResult = ESubmitResults::SUBMIT_CANCELED;
|
|
ParentFrame.Pin()->RequestDestroyWindow();
|
|
|
|
return FReply::Handled();
|
|
}
|
|
|
|
|
|
bool SSourceControlSubmitWidget::IsOKEnabled() const
|
|
{
|
|
return !ChangeListDescriptionTextCtrl->GetText().IsEmpty();
|
|
}
|
|
|
|
|
|
EVisibility SSourceControlSubmitWidget::IsWarningPanelVisible() const
|
|
{
|
|
return IsOKEnabled()? EVisibility::Hidden : EVisibility::Visible;
|
|
}
|
|
|
|
|
|
void SSourceControlSubmitWidget::OnCheckStateChanged_KeepCheckedOut(ECheckBoxState InState)
|
|
{
|
|
KeepCheckedOut = InState;
|
|
}
|
|
|
|
|
|
ECheckBoxState SSourceControlSubmitWidget::GetKeepCheckedOut() const
|
|
{
|
|
return KeepCheckedOut;
|
|
}
|
|
|
|
|
|
TSharedRef<ITableRow> SSourceControlSubmitWidget::OnGenerateRowForList(TSharedPtr<FSubmitItem> 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_FileLabel)
|
|
{
|
|
if (SortMode == EColumnSortMode::Ascending)
|
|
{
|
|
ListViewItems.Sort([](const TSharedPtr<FSubmitItem>& A, const TSharedPtr<FSubmitItem>& B) {
|
|
return A->GetDisplayName().ToString() < B->GetDisplayName().ToString(); });
|
|
}
|
|
else if (SortMode == EColumnSortMode::Descending)
|
|
{
|
|
ListViewItems.Sort([](const TSharedPtr<FSubmitItem>& A, const TSharedPtr<FSubmitItem>& B) {
|
|
return A->GetDisplayName().ToString() >= B->GetDisplayName().ToString(); });
|
|
}
|
|
}
|
|
else if (SortByColumn == SSourceControlSubmitWidgetDefs::ColumnID_IconLabel)
|
|
{
|
|
if (SortMode == EColumnSortMode::Ascending)
|
|
{
|
|
ListViewItems.Sort([](const TSharedPtr<FSubmitItem>& A, const TSharedPtr<FSubmitItem>& B) {
|
|
return A->GetIconName().ToString() < B->GetIconName().ToString(); });
|
|
}
|
|
else if (SortMode == EColumnSortMode::Descending)
|
|
{
|
|
ListViewItems.Sort([](const TSharedPtr<FSubmitItem>& A, const TSharedPtr<FSubmitItem>& B) {
|
|
return A->GetIconName().ToString() >= B->GetIconName().ToString(); });
|
|
}
|
|
}
|
|
}
|
|
|
|
|
|
TWeakPtr<SNotificationItem> FSourceControlWindows::ChoosePackagesToCheckInNotification;
|
|
|
|
void FSourceControlWindows::ChoosePackagesToCheckInCompleted(const TArray<UPackage*>& LoadedPackages, const TArray<FString>& PackageNames, const TArray<FString>& ConfigFiles)
|
|
{
|
|
if (ChoosePackagesToCheckInNotification.IsValid())
|
|
{
|
|
ChoosePackagesToCheckInNotification.Pin()->ExpireAndFadeout();
|
|
}
|
|
ChoosePackagesToCheckInNotification.Reset();
|
|
|
|
check(PackageNames.Num() > 0 || ConfigFiles.Num() > 0);
|
|
|
|
// Prompt the user to ask if they would like to first save any dirty packages they are trying to check-in
|
|
const FEditorFileUtils::EPromptReturnCode UserResponse = FEditorFileUtils::PromptForCheckoutAndSave(LoadedPackages, true, true);
|
|
|
|
// If the user elected to save dirty packages, but one or more of the packages failed to save properly OR if the user
|
|
// canceled out of the prompt, don't follow through on the check-in process
|
|
const bool bShouldProceed = (UserResponse == FEditorFileUtils::EPromptReturnCode::PR_Success || UserResponse == FEditorFileUtils::EPromptReturnCode::PR_Declined);
|
|
if (bShouldProceed)
|
|
{
|
|
TArray<FString> PendingDeletePaths;
|
|
PendingDeletePaths.Add(FPaths::ConvertRelativePathToFull(FPaths::EngineContentDir()));
|
|
PendingDeletePaths.Add(FPaths::ConvertRelativePathToFull(FPaths::GameContentDir()));
|
|
PendingDeletePaths.Add(FPaths::ConvertRelativePathToFull(FPaths::GameConfigDir()));
|
|
|
|
const bool bUseSourceControlStateCache = true;
|
|
PromptForCheckin(bUseSourceControlStateCache, PackageNames, PendingDeletePaths, ConfigFiles);
|
|
}
|
|
else
|
|
{
|
|
// If a failure occurred, alert the user that the check-in was aborted. This warning shouldn't be necessary if the user cancelled
|
|
// from the dialog, because they obviously intended to cancel the whole operation.
|
|
if (UserResponse == FEditorFileUtils::EPromptReturnCode::PR_Failure)
|
|
{
|
|
FMessageDialog::Open(EAppMsgType::Ok, NSLOCTEXT("UnrealEd", "SCC_Checkin_Aborted", "Check-in aborted as a result of save failure."));
|
|
}
|
|
}
|
|
}
|
|
|
|
void FSourceControlWindows::ChoosePackagesToCheckInCancelled(FSourceControlOperationRef InOperation)
|
|
{
|
|
ISourceControlProvider& SourceControlProvider = ISourceControlModule::Get().GetProvider();
|
|
SourceControlProvider.CancelOperation(InOperation);
|
|
|
|
if (ChoosePackagesToCheckInNotification.IsValid())
|
|
{
|
|
ChoosePackagesToCheckInNotification.Pin()->ExpireAndFadeout();
|
|
}
|
|
ChoosePackagesToCheckInNotification.Reset();
|
|
}
|
|
|
|
void FSourceControlWindows::ChoosePackagesToCheckInCallback(const FSourceControlOperationRef& InOperation, ECommandResult::Type InResult)
|
|
{
|
|
if (ChoosePackagesToCheckInNotification.IsValid())
|
|
{
|
|
ChoosePackagesToCheckInNotification.Pin()->ExpireAndFadeout();
|
|
}
|
|
ChoosePackagesToCheckInNotification.Reset();
|
|
|
|
if (InResult == ECommandResult::Succeeded)
|
|
{
|
|
// Get a list of all the checked out packages
|
|
TArray<FString> PackageNames;
|
|
TArray<UPackage*> LoadedPackages;
|
|
TMap<FString, FSourceControlStatePtr> PackageStates;
|
|
FEditorFileUtils::FindAllSubmittablePackageFiles(PackageStates, true);
|
|
|
|
for (TMap<FString, FSourceControlStatePtr>::TConstIterator PackageIter(PackageStates); PackageIter; ++PackageIter)
|
|
{
|
|
const FString PackageName = *PackageIter.Key();
|
|
const FSourceControlStatePtr CurPackageSCCState = PackageIter.Value();
|
|
|
|
UPackage* Package = FindPackage(nullptr, *PackageName);
|
|
if (Package != nullptr)
|
|
{
|
|
LoadedPackages.Add(Package);
|
|
}
|
|
|
|
PackageNames.Add(PackageName);
|
|
}
|
|
|
|
// Get a list of all the checked out config files
|
|
TMap<FString, FSourceControlStatePtr> ConfigFileStates;
|
|
TArray<FString> ConfigFilesToSubmit;
|
|
FEditorFileUtils::FindAllSubmittableConfigFiles(ConfigFileStates);
|
|
for (TMap<FString, FSourceControlStatePtr>::TConstIterator It(ConfigFileStates); It; ++It)
|
|
{
|
|
ConfigFilesToSubmit.Add(It.Key());
|
|
}
|
|
|
|
if (PackageNames.Num() > 0 || ConfigFilesToSubmit.Num() > 0)
|
|
{
|
|
ChoosePackagesToCheckInCompleted(LoadedPackages, PackageNames, ConfigFilesToSubmit);
|
|
}
|
|
else
|
|
{
|
|
FMessageLog EditorErrors("EditorErrors");
|
|
EditorErrors.Warning(LOCTEXT("NoAssetsToCheckIn", "No assets to check in!"));
|
|
EditorErrors.Notify();
|
|
}
|
|
}
|
|
else if (InResult == ECommandResult::Failed)
|
|
{
|
|
FMessageLog EditorErrors("EditorErrors");
|
|
EditorErrors.Warning(LOCTEXT("CheckInOperationFailed", "Failed checking source control status!"));
|
|
EditorErrors.Notify();
|
|
}
|
|
}
|
|
|
|
void FSourceControlWindows::ChoosePackagesToCheckIn()
|
|
{
|
|
if (ISourceControlModule::Get().IsEnabled())
|
|
{
|
|
if (ISourceControlModule::Get().GetProvider().IsAvailable())
|
|
{
|
|
// make sure we update the SCC status of all packages (this could take a long time, so we will run it as a background task)
|
|
TArray<FString> Packages;
|
|
FEditorFileUtils::FindAllPackageFiles(Packages);
|
|
|
|
// Get list of filenames corresponding to packages
|
|
TArray<FString> Filenames = SourceControlHelpers::PackageFilenames(Packages);
|
|
|
|
// Add game config files to the list
|
|
FEditorFileUtils::FindAllConfigFiles(Filenames);
|
|
|
|
// Add pending delete paths to the list
|
|
Filenames.Add(FPaths::ConvertRelativePathToFull(FPaths::EngineContentDir()));
|
|
Filenames.Add(FPaths::ConvertRelativePathToFull(FPaths::GameContentDir()));
|
|
Filenames.Add(FPaths::ConvertRelativePathToFull(FPaths::GameConfigDir()));
|
|
|
|
ISourceControlProvider& SourceControlProvider = ISourceControlModule::Get().GetProvider();
|
|
FSourceControlOperationRef Operation = ISourceControlOperation::Create<FUpdateStatus>();
|
|
StaticCastSharedRef<FUpdateStatus>(Operation)->SetCheckingAllFiles(true);
|
|
SourceControlProvider.Execute(Operation, Filenames, EConcurrency::Asynchronous, FSourceControlOperationComplete::CreateStatic(&FSourceControlWindows::ChoosePackagesToCheckInCallback));
|
|
|
|
if (ChoosePackagesToCheckInNotification.IsValid())
|
|
{
|
|
ChoosePackagesToCheckInNotification.Pin()->ExpireAndFadeout();
|
|
}
|
|
|
|
FNotificationInfo Info(LOCTEXT("ChooseAssetsToCheckInIndicator", "Checking for assets to check in..."));
|
|
Info.bFireAndForget = false;
|
|
Info.ExpireDuration = 0.0f;
|
|
Info.FadeOutDuration = 1.0f;
|
|
|
|
if (SourceControlProvider.CanCancelOperation(Operation))
|
|
{
|
|
Info.ButtonDetails.Add(FNotificationButtonInfo(
|
|
LOCTEXT("ChoosePackagesToCheckIn_CancelButton", "Cancel"),
|
|
LOCTEXT("ChoosePackagesToCheckIn_CancelButtonTooltip", "Cancel the check in operation."),
|
|
FSimpleDelegate::CreateStatic(&FSourceControlWindows::ChoosePackagesToCheckInCancelled, Operation)
|
|
));
|
|
}
|
|
|
|
ChoosePackagesToCheckInNotification = FSlateNotificationManager::Get().AddNotification(Info);
|
|
|
|
if (ChoosePackagesToCheckInNotification.IsValid())
|
|
{
|
|
ChoosePackagesToCheckInNotification.Pin()->SetCompletionState(SNotificationItem::CS_Pending);
|
|
}
|
|
}
|
|
else
|
|
{
|
|
FMessageLog EditorErrors("EditorErrors");
|
|
EditorErrors.Warning(LOCTEXT("NoSCCConnection", "No connection to source control available!"))
|
|
->AddToken(FDocumentationToken::Create(TEXT("Engine/UI/SourceControl")));
|
|
EditorErrors.Notify();
|
|
}
|
|
}
|
|
}
|
|
|
|
bool FSourceControlWindows::CanChoosePackagesToCheckIn()
|
|
{
|
|
return !ChoosePackagesToCheckInNotification.IsValid();
|
|
}
|
|
|
|
|
|
bool FSourceControlWindows::PromptForCheckin(bool bUseSourceControlStateCache, const TArray<FString>& InPackageNames, const TArray<FString>& InPendingDeletePaths, const TArray<FString>& InConfigFiles)
|
|
{
|
|
ISourceControlProvider& SourceControlProvider = ISourceControlModule::Get().GetProvider();
|
|
|
|
bool bCheckInSuccess = true;
|
|
|
|
// Get filenames for packages and config to be checked in
|
|
TArray<FString> AllFiles = SourceControlHelpers::PackageFilenames(InPackageNames);
|
|
AllFiles.Append(InConfigFiles);
|
|
|
|
// Prepare a list of files to have their states updated
|
|
if (!bUseSourceControlStateCache)
|
|
{
|
|
TArray<FString> UpdateRequest;
|
|
UpdateRequest.Append(AllFiles);
|
|
|
|
// If there are pending delete paths to update, add them here.
|
|
UpdateRequest.Append(InPendingDeletePaths);
|
|
|
|
// Force an update on everything that's been requested
|
|
if (UpdateRequest.Num() > 0)
|
|
{
|
|
SourceControlProvider.Execute(ISourceControlOperation::Create<FUpdateStatus>(), UpdateRequest);
|
|
}
|
|
}
|
|
|
|
// Get file status of packages and config
|
|
TArray<FSourceControlStateRef> States;
|
|
SourceControlProvider.GetState(AllFiles, States, EStateCacheUsage::Use);
|
|
|
|
if (InPendingDeletePaths.Num() > 0)
|
|
{
|
|
// Get any files pending delete
|
|
TArray<FSourceControlStateRef> PendingDeleteItems = SourceControlProvider.GetCachedStateByPredicate(
|
|
[](const FSourceControlStateRef& State) { return State->IsDeleted(); }
|
|
);
|
|
|
|
// And append them to the list
|
|
States.Append(PendingDeleteItems);
|
|
}
|
|
|
|
if (States.Num())
|
|
{
|
|
TSharedRef<SWindow> NewWindow = SNew(SWindow)
|
|
.Title(NSLOCTEXT("SourceControl.SubmitWindow", "Title", "Submit Files"))
|
|
.SizingRule(ESizingRule::UserSized)
|
|
.ClientSize(FVector2D(600, 400))
|
|
.SupportsMaximize(true)
|
|
.SupportsMinimize(false);
|
|
|
|
TSharedRef<SSourceControlSubmitWidget> SourceControlWidget =
|
|
SNew(SSourceControlSubmitWidget)
|
|
.ParentWindow(NewWindow)
|
|
.Items(States);
|
|
|
|
NewWindow->SetContent(
|
|
SourceControlWidget
|
|
);
|
|
|
|
FSlateApplication::Get().AddModalWindow(NewWindow, NULL);
|
|
|
|
if (SourceControlWidget->GetResult() == ESubmitResults::SUBMIT_ACCEPTED)
|
|
{
|
|
//Get description from the dialog
|
|
FChangeListDescription Description;
|
|
SourceControlWidget->FillChangeListDescription(Description);
|
|
|
|
//revert all unchanged files that were submitted
|
|
if ( Description.FilesForSubmit.Num() > 0 )
|
|
{
|
|
SourceControlHelpers::RevertUnchangedFiles(SourceControlProvider, Description.FilesForSubmit);
|
|
|
|
//make sure all files are still checked out
|
|
for (int32 VerifyIndex = Description.FilesForSubmit.Num()-1; VerifyIndex >= 0; --VerifyIndex)
|
|
{
|
|
FSourceControlStatePtr SourceControlState = SourceControlProvider.GetState(Description.FilesForSubmit[VerifyIndex], EStateCacheUsage::Use);
|
|
if( SourceControlState.IsValid() && !SourceControlState->IsCheckedOut() && !SourceControlState->IsAdded() && !SourceControlState->IsDeleted() )
|
|
{
|
|
Description.FilesForSubmit.RemoveAt(VerifyIndex);
|
|
}
|
|
}
|
|
}
|
|
|
|
TArray<FString> CombinedFileList = Description.FilesForAdd;
|
|
CombinedFileList.Append(Description.FilesForSubmit);
|
|
|
|
if(Description.FilesForAdd.Num() > 0)
|
|
{
|
|
bCheckInSuccess &= (SourceControlProvider.Execute(ISourceControlOperation::Create<FMarkForAdd>(), Description.FilesForAdd) == ECommandResult::Succeeded);
|
|
}
|
|
|
|
if(CombinedFileList.Num() > 0)
|
|
{
|
|
TSharedRef<FCheckIn, ESPMode::ThreadSafe> CheckInOperation = ISourceControlOperation::Create<FCheckIn>();
|
|
CheckInOperation->SetDescription(Description.Description);
|
|
bCheckInSuccess &= (SourceControlProvider.Execute(CheckInOperation, CombinedFileList) == ECommandResult::Succeeded);
|
|
|
|
if(bCheckInSuccess)
|
|
{
|
|
// report success with a notification
|
|
FNotificationInfo Info(CheckInOperation->GetSuccessMessage());
|
|
Info.ExpireDuration = 8.0f;
|
|
Info.HyperlinkText = LOCTEXT("SCC_Checkin_ShowLog", "Show Message Log");
|
|
Info.Hyperlink = FSimpleDelegate::CreateStatic([](){ FMessageLog("SourceControl").Open(EMessageSeverity::Info, true); });
|
|
FSlateNotificationManager::Get().AddNotification(Info);
|
|
|
|
// also add to the log
|
|
FMessageLog("SourceControl").Info(CheckInOperation->GetSuccessMessage());
|
|
}
|
|
}
|
|
|
|
if(!bCheckInSuccess)
|
|
{
|
|
FMessageLog("SourceControl").Notify(LOCTEXT("SCC_Checkin_Failed", "Failed to check in files!"));
|
|
}
|
|
// If we checked in ok, do we want to to re-check out the files we just checked in?
|
|
else
|
|
{
|
|
if( SourceControlWidget->WantToKeepCheckedOut() == true )
|
|
{
|
|
// Re-check out files
|
|
if(SourceControlProvider.Execute(ISourceControlOperation::Create<FCheckOut>(), CombinedFileList) != ECommandResult::Succeeded)
|
|
{
|
|
FMessageDialog::Open( EAppMsgType::Ok, LOCTEXT("SCC_Checkin_ReCheckOutFailed", "Failed to re-check out files.") );
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
return bCheckInSuccess;
|
|
}
|
|
|
|
|
|
#undef LOCTEXT_NAMESPACE
|
|
|
|
#endif // SOURCE_CONTROL_WITH_SLATE
|