This repository has been archived on 2021-12-21. You can view files and clone it, but cannot push or open issues or pull requests.
Bookworm/Plugins/UE4GitPlugin-2.17-beta/Source/GitSourceControl/Private/SGitSourceControlSettings.cpp

751 lines
27 KiB
C++
Raw Normal View History

2021-11-17 11:35:23 +00:00
// Copyright (c) 2014-2020 Sebastien Rombauts (sebastien.rombauts@gmail.com)
//
// Distributed under the MIT License (MIT) (See accompanying file LICENSE.txt
// or copy at http://opensource.org/licenses/MIT)
#include "SGitSourceControlSettings.h"
#include "Fonts/SlateFontInfo.h"
#include "Misc/App.h"
#include "Misc/FileHelper.h"
#include "Misc/Paths.h"
#include "Modules/ModuleManager.h"
#include "Styling/SlateTypes.h"
#include "Widgets/SBoxPanel.h"
#include "Widgets/Text/STextBlock.h"
#include "Widgets/Input/SButton.h"
#include "Widgets/Input/SCheckBox.h"
#include "Widgets/Input/SEditableTextBox.h"
#include "Widgets/Input/SFilePathPicker.h"
#include "Widgets/Input/SMultiLineEditableTextBox.h"
#include "Widgets/Layout/SBorder.h"
#include "Widgets/Layout/SSeparator.h"
#include "Widgets/Notifications/SNotificationList.h"
#include "Framework/Notifications/NotificationManager.h"
#include "EditorDirectories.h"
#include "EditorStyleSet.h"
#include "SourceControlOperations.h"
#include "GitSourceControlModule.h"
#include "GitSourceControlUtils.h"
#define LOCTEXT_NAMESPACE "SGitSourceControlSettings"
void SGitSourceControlSettings::Construct(const FArguments& InArgs)
{
const FSlateFontInfo Font = FEditorStyle::GetFontStyle(TEXT("SourceControl.LoginWindow.Font"));
bAutoCreateGitIgnore = true;
bAutoCreateReadme = true;
bAutoCreateGitAttributes = false;
bAutoInitialCommit = true;
InitialCommitMessage = LOCTEXT("InitialCommitMessage", "Initial commit");
const FText FileFilterType = NSLOCTEXT("GitSourceControl", "Executables", "Executables");
#if PLATFORM_WINDOWS
const FString FileFilterText = FString::Printf(TEXT("%s (*.exe)|*.exe"), *FileFilterType.ToString());
#else
const FString FileFilterText = FString::Printf(TEXT("%s"), *FileFilterType.ToString());
#endif
ReadmeContent = FText::FromString(FString(TEXT("# ")) + FApp::GetProjectName() + "\n\nDeveloped with Unreal Engine 4\n");
ChildSlot
[
SNew(SBorder)
.BorderImage( FEditorStyle::GetBrush("DetailsView.CategoryBottom"))
.Padding(FMargin(0.0f, 3.0f, 0.0f, 0.0f))
[
SNew(SVerticalBox)
// Path to the Git command line executable
+SVerticalBox::Slot()
.AutoHeight()
.Padding(2.0f)
.VAlign(VAlign_Center)
[
SNew(SHorizontalBox)
.ToolTipText(LOCTEXT("BinaryPathLabel_Tooltip", "Path to Git binary"))
+SHorizontalBox::Slot()
.FillWidth(1.0f)
[
SNew(STextBlock)
.Text(LOCTEXT("BinaryPathLabel", "Git Path"))
.Font(Font)
]
+SHorizontalBox::Slot()
.FillWidth(2.0f)
[
SNew(SFilePathPicker)
.BrowseButtonImage(FEditorStyle::GetBrush("PropertyWindow.Button_Ellipsis"))
.BrowseButtonStyle(FEditorStyle::Get(), "HoverHintOnly")
.BrowseDirectory(FEditorDirectories::Get().GetLastDirectory(ELastDirectory::GENERIC_OPEN))
.BrowseTitle(LOCTEXT("BinaryPathBrowseTitle", "File picker..."))
.FilePath(this, &SGitSourceControlSettings::GetBinaryPathString)
.FileTypeFilter(FileFilterText)
.OnPathPicked(this, &SGitSourceControlSettings::OnBinaryPathPicked)
]
]
// Root of the local repository
+SVerticalBox::Slot()
.AutoHeight()
.Padding(2.0f)
.VAlign(VAlign_Center)
[
SNew(SHorizontalBox)
.ToolTipText(LOCTEXT("RepositoryRootLabel_Tooltip", "Path to the root of the Git repository"))
+SHorizontalBox::Slot()
.FillWidth(1.0f)
[
SNew(STextBlock)
.Text(LOCTEXT("RepositoryRootLabel", "Root of the repository"))
.Font(Font)
]
+SHorizontalBox::Slot()
.FillWidth(2.0f)
[
SNew(STextBlock)
.Text(this, &SGitSourceControlSettings::GetPathToRepositoryRoot)
.Font(Font)
]
]
// User Name
+SVerticalBox::Slot()
.AutoHeight()
.Padding(2.0f)
.VAlign(VAlign_Center)
[
SNew(SHorizontalBox)
.ToolTipText(LOCTEXT("GitUserName_Tooltip", "User name configured for the Git repository"))
+SHorizontalBox::Slot()
.FillWidth(1.0f)
[
SNew(STextBlock)
.Text(LOCTEXT("GitUserName", "User Name"))
.Font(Font)
]
+SHorizontalBox::Slot()
.FillWidth(2.0f)
[
SNew(STextBlock)
.Text(this, &SGitSourceControlSettings::GetUserName)
.Font(Font)
]
]
// User e-mail
+SVerticalBox::Slot()
.FillHeight(1.0f)
.Padding(2.0f)
.VAlign(VAlign_Center)
[
SNew(SHorizontalBox)
.ToolTipText(LOCTEXT("GitUserEmail_Tooltip", "User e-mail configured for the Git repository"))
+SHorizontalBox::Slot()
.FillWidth(1.0f)
[
SNew(STextBlock)
.Text(LOCTEXT("GitUserEmail", "E-Mail"))
.Font(Font)
]
+SHorizontalBox::Slot()
.FillWidth(2.0f)
[
SNew(STextBlock)
.Text(this, &SGitSourceControlSettings::GetUserEmail)
.Font(Font)
]
]
// Separator
+SVerticalBox::Slot()
.AutoHeight()
.Padding(2.0f)
.VAlign(VAlign_Center)
[
SNew(SSeparator)
]
// Explanation text
+SVerticalBox::Slot()
.FillHeight(1.0f)
.Padding(2.0f)
.VAlign(VAlign_Center)
[
SNew(SHorizontalBox)
.Visibility(this, &SGitSourceControlSettings::MustInitializeGitRepository)
+SHorizontalBox::Slot()
.FillWidth(1.0f)
.HAlign(HAlign_Center)
[
SNew(STextBlock)
.Text(LOCTEXT("RepositoryNotFound", "Current Project is not contained in a Git Repository. Fill the form below to initialize a new Repository."))
.ToolTipText(LOCTEXT("RepositoryNotFound_Tooltip", "No Repository found at the level or above the current Project"))
.Font(Font)
]
]
// Option to configure the URL of the default remote 'origin'
// TODO: option to configure the name of the remote instead of the default origin
+SVerticalBox::Slot()
.AutoHeight()
.Padding(2.0f)
.VAlign(VAlign_Center)
[
SNew(SHorizontalBox)
.Visibility(this, &SGitSourceControlSettings::MustInitializeGitRepository)
.ToolTipText(LOCTEXT("ConfigureOrigin_Tooltip", "Configure the URL of the default remote 'origin'"))
+SHorizontalBox::Slot()
.FillWidth(1.0f)
[
SNew(STextBlock)
.Text(LOCTEXT("ConfigureOrigin", "URL of the remote server 'origin'"))
.Font(Font)
]
+SHorizontalBox::Slot()
.FillWidth(2.0f)
.VAlign(VAlign_Center)
[
SNew(SEditableTextBox)
.Text(this, &SGitSourceControlSettings::GetRemoteUrl)
.OnTextCommitted(this, &SGitSourceControlSettings::OnRemoteUrlCommited)
.Font(Font)
]
]
// Option to add a proper .gitignore file (true by default)
+SVerticalBox::Slot()
.AutoHeight()
.Padding(2.0f)
.VAlign(VAlign_Center)
[
SNew(SHorizontalBox)
.Visibility(this, &SGitSourceControlSettings::MustInitializeGitRepository)
.ToolTipText(LOCTEXT("CreateGitIgnore_Tooltip", "Create and add a standard '.gitignore' file"))
+SHorizontalBox::Slot()
.FillWidth(0.1f)
[
SNew(SCheckBox)
.IsChecked(ECheckBoxState::Checked)
.OnCheckStateChanged(this, &SGitSourceControlSettings::OnCheckedCreateGitIgnore)
]
+SHorizontalBox::Slot()
.FillWidth(2.9f)
.VAlign(VAlign_Center)
[
SNew(STextBlock)
.Text(LOCTEXT("CreateGitIgnore", "Add a .gitignore file"))
.Font(Font)
]
]
// Option to add a README.md file with custom content
+SVerticalBox::Slot()
.AutoHeight()
.Padding(2.0f)
.VAlign(VAlign_Center)
[
SNew(SHorizontalBox)
.Visibility(this, &SGitSourceControlSettings::MustInitializeGitRepository)
.ToolTipText(LOCTEXT("CreateReadme_Tooltip", "Add a README.md file"))
+SHorizontalBox::Slot()
.FillWidth(0.1f)
[
SNew(SCheckBox)
.IsChecked(ECheckBoxState::Checked)
.OnCheckStateChanged(this, &SGitSourceControlSettings::OnCheckedCreateReadme)
]
+SHorizontalBox::Slot()
.FillWidth(0.9f)
.VAlign(VAlign_Center)
[
SNew(STextBlock)
.Text(LOCTEXT("CreateReadme", "Add a basic README.md file"))
.Font(Font)
]
+SHorizontalBox::Slot()
.FillWidth(2.0f)
.Padding(2.0f)
[
SNew(SMultiLineEditableTextBox)
.Text(this, &SGitSourceControlSettings::GetReadmeContent)
.OnTextCommitted(this, &SGitSourceControlSettings::OnReadmeContentCommited)
.IsEnabled(this, &SGitSourceControlSettings::GetAutoCreateReadme)
.SelectAllTextWhenFocused(true)
.Font(Font)
]
]
// Option to add a proper .gitattributes file for Git LFS (false by default)
+SVerticalBox::Slot()
.AutoHeight()
.Padding(2.0f)
.VAlign(VAlign_Center)
[
SNew(SHorizontalBox)
.Visibility(this, &SGitSourceControlSettings::MustInitializeGitRepository)
.ToolTipText(LOCTEXT("CreateGitAttributes_Tooltip", "Create and add a '.gitattributes' file to enable Git LFS for the whole 'Content/' directory (needs Git LFS extensions to be installed)."))
+SHorizontalBox::Slot()
.FillWidth(0.1f)
[
SNew(SCheckBox)
.IsChecked(ECheckBoxState::Unchecked)
.OnCheckStateChanged(this, &SGitSourceControlSettings::OnCheckedCreateGitAttributes)
.IsEnabled(this, &SGitSourceControlSettings::CanInitializeGitLfs)
]
+SHorizontalBox::Slot()
.FillWidth(2.9f)
.VAlign(VAlign_Center)
[
SNew(STextBlock)
.Text(LOCTEXT("CreateGitAttributes", "Add a .gitattributes file to enable Git LFS"))
.Font(Font)
]
]
// Option to use the Git LFS File Locking workflow (false by default)
// Enabled even after init to switch it off in case of no network
// TODO LFS turning it off afterwards does not work because all files are readonly !
+SVerticalBox::Slot()
.AutoHeight()
.Padding(2.0f)
.VAlign(VAlign_Center)
[
SNew(SHorizontalBox)
.ToolTipText(LOCTEXT("UseGitLfsLocking_Tooltip", "Uses Git LFS 2 File Locking workflow (CheckOut and Commit/Push)."))
+SHorizontalBox::Slot()
.FillWidth(0.1f)
[
SNew(SCheckBox)
.IsChecked(SGitSourceControlSettings::IsUsingGitLfsLocking())
.OnCheckStateChanged(this, &SGitSourceControlSettings::OnCheckedUseGitLfsLocking)
.IsEnabled(this, &SGitSourceControlSettings::CanUseGitLfsLocking)
]
+SHorizontalBox::Slot()
.FillWidth(0.9f)
.VAlign(VAlign_Center)
[
SNew(STextBlock)
.Text(LOCTEXT("UseGitLfsLocking", "Uses Git LFS 2 File Locking workflow"))
.Font(Font)
]
// Username credential used to access the Git LFS 2 File Locks server
+SHorizontalBox::Slot()
.FillWidth(2.0f)
.VAlign(VAlign_Center)
[
SNew(SEditableTextBox)
.Text(this, &SGitSourceControlSettings::GetLfsUserName)
.OnTextCommitted(this, &SGitSourceControlSettings::OnLfsUserNameCommited)
.IsEnabled(this, &SGitSourceControlSettings::GetIsUsingGitLfsLocking)
.HintText(LOCTEXT("LfsUserName_Hint", "Username to lock files on the LFS server"))
.Font(Font)
]
]
// Option to Make the initial Git commit with custom message
+SVerticalBox::Slot()
.AutoHeight()
.Padding(2.0f)
.VAlign(VAlign_Center)
[
SNew(SHorizontalBox)
.Visibility(this, &SGitSourceControlSettings::MustInitializeGitRepository)
.ToolTipText(LOCTEXT("InitialGitCommit_Tooltip", "Make the initial Git commit"))
+SHorizontalBox::Slot()
.FillWidth(0.1f)
[
SNew(SCheckBox)
.IsChecked(ECheckBoxState::Checked)
.OnCheckStateChanged(this, &SGitSourceControlSettings::OnCheckedInitialCommit)
]
+SHorizontalBox::Slot()
.FillWidth(0.9f)
.VAlign(VAlign_Center)
[
SNew(STextBlock)
.Text(LOCTEXT("InitialGitCommit", "Make the initial Git commit"))
.Font(Font)
]
+SHorizontalBox::Slot()
.FillWidth(2.0f)
.Padding(2.0f)
[
SNew(SMultiLineEditableTextBox)
.Text(this, &SGitSourceControlSettings::GetInitialCommitMessage)
.OnTextCommitted(this, &SGitSourceControlSettings::OnInitialCommitMessageCommited)
.IsEnabled(this, &SGitSourceControlSettings::GetAutoInitialCommit)
.SelectAllTextWhenFocused(true)
.Font(Font)
]
]
// Button to initialize the project with Git, create .gitignore/.gitattributes files, and make the first commit)
+SVerticalBox::Slot()
.FillHeight(2.5f)
.Padding(4.0f)
.VAlign(VAlign_Center)
[
SNew(SHorizontalBox)
.Visibility(this, &SGitSourceControlSettings::MustInitializeGitRepository)
+SHorizontalBox::Slot()
.FillWidth(1.0f)
[
SNew(SButton)
.Text(LOCTEXT("GitInitRepository", "Initialize project with Git"))
.ToolTipText(LOCTEXT("GitInitRepository_Tooltip", "Initialize current project as a new Git repository"))
.OnClicked(this, &SGitSourceControlSettings::OnClickedInitializeGitRepository)
.IsEnabled(this, &SGitSourceControlSettings::CanInitializeGitRepository)
.HAlign(HAlign_Center)
.ContentPadding(6)
]
]
]
];
}
SGitSourceControlSettings::~SGitSourceControlSettings()
{
RemoveInProgressNotification();
}
FString SGitSourceControlSettings::GetBinaryPathString() const
{
const FGitSourceControlModule& GitSourceControl = FModuleManager::GetModuleChecked<FGitSourceControlModule>("GitSourceControl");
return GitSourceControl.AccessSettings().GetBinaryPath();
}
void SGitSourceControlSettings::OnBinaryPathPicked( const FString& PickedPath ) const
{
FGitSourceControlModule& GitSourceControl = FModuleManager::GetModuleChecked<FGitSourceControlModule>("GitSourceControl");
FString PickedFullPath = FPaths::ConvertRelativePathToFull(PickedPath);
const bool bChanged = GitSourceControl.AccessSettings().SetBinaryPath(PickedFullPath);
if(bChanged)
{
// Re-Check provided git binary path for each change
GitSourceControl.GetProvider().CheckGitAvailability();
if(GitSourceControl.GetProvider().IsGitAvailable())
{
GitSourceControl.SaveSettings();
}
}
}
FText SGitSourceControlSettings::GetPathToRepositoryRoot() const
{
const FGitSourceControlModule& GitSourceControl = FModuleManager::GetModuleChecked<FGitSourceControlModule>("GitSourceControl");
return FText::FromString(GitSourceControl.GetProvider().GetPathToRepositoryRoot());
}
FText SGitSourceControlSettings::GetUserName() const
{
const FGitSourceControlModule& GitSourceControl = FModuleManager::GetModuleChecked<FGitSourceControlModule>("GitSourceControl");
return FText::FromString(GitSourceControl.GetProvider().GetUserName());
}
FText SGitSourceControlSettings::GetUserEmail() const
{
const FGitSourceControlModule& GitSourceControl = FModuleManager::GetModuleChecked<FGitSourceControlModule>("GitSourceControl");
return FText::FromString(GitSourceControl.GetProvider().GetUserEmail());
}
EVisibility SGitSourceControlSettings::MustInitializeGitRepository() const
{
const FGitSourceControlModule& GitSourceControl = FModuleManager::GetModuleChecked<FGitSourceControlModule>("GitSourceControl");
const bool bGitAvailable = GitSourceControl.GetProvider().IsGitAvailable();
const bool bGitRepositoryFound = GitSourceControl.GetProvider().IsEnabled();
return (bGitAvailable && !bGitRepositoryFound) ? EVisibility::Visible : EVisibility::Collapsed;
}
bool SGitSourceControlSettings::CanInitializeGitRepository() const
{
const FGitSourceControlModule& GitSourceControl = FModuleManager::GetModuleChecked<FGitSourceControlModule>("GitSourceControl");
const bool bGitAvailable = GitSourceControl.GetProvider().IsGitAvailable();
const bool bGitRepositoryFound = GitSourceControl.GetProvider().IsEnabled();
const FString LfsUserName = GitSourceControl.AccessSettings().GetLfsUserName();
const bool bIsUsingGitLfsLocking = GitSourceControl.AccessSettings().IsUsingGitLfsLocking();
const bool bGitLfsConfigOk = !bIsUsingGitLfsLocking || !LfsUserName.IsEmpty();
const bool bInitialCommitConfigOk = !bAutoInitialCommit || !InitialCommitMessage.IsEmpty();
return (bGitAvailable && !bGitRepositoryFound && bGitLfsConfigOk && bInitialCommitConfigOk);
}
bool SGitSourceControlSettings::CanInitializeGitLfs() const
{
const FGitSourceControlModule& GitSourceControl = FModuleManager::GetModuleChecked<FGitSourceControlModule>("GitSourceControl");
const FString& PathToGitBinary = GitSourceControl.AccessSettings().GetBinaryPath();
const bool bGitLfsAvailable = GitSourceControl.GetProvider().GetGitVersion().bHasGitLfs;
return bGitLfsAvailable;
}
bool SGitSourceControlSettings::CanUseGitLfsLocking() const
{
const FGitSourceControlModule& GitSourceControl = FModuleManager::GetModuleChecked<FGitSourceControlModule>("GitSourceControl");
const bool bGitLfsLockingAvailable = GitSourceControl.GetProvider().GetGitVersion().bHasGitLfsLocking;
// TODO LFS SRombauts : check if .gitattributes file is present and if Content/ is already tracked!
const bool bGitAttributesCreated = true;
return (bGitLfsLockingAvailable && (bAutoCreateGitAttributes || bGitAttributesCreated));
}
FReply SGitSourceControlSettings::OnClickedInitializeGitRepository()
{
FGitSourceControlModule& GitSourceControl = FModuleManager::GetModuleChecked<FGitSourceControlModule>("GitSourceControl");
const FString& PathToGitBinary = GitSourceControl.AccessSettings().GetBinaryPath();
const FString PathToProjectDir = FPaths::ConvertRelativePathToFull(FPaths::ProjectDir());
TArray<FString> InfoMessages;
TArray<FString> ErrorMessages;
// 1.a. Synchronous (very quick) "git init" operation: initialize a Git local repository with a .git/ subdirectory
GitSourceControlUtils::RunCommand(TEXT("init"), PathToGitBinary, PathToProjectDir, TArray<FString>(), TArray<FString>(), InfoMessages, ErrorMessages);
// 1.b. Synchronous (very quick) "git remote add" operation: configure the URL of the default remote server 'origin' if specified
if(!RemoteUrl.IsEmpty())
{
TArray<FString> Parameters;
Parameters.Add(TEXT("add origin"));
Parameters.Add(RemoteUrl.ToString());
GitSourceControlUtils::RunCommand(TEXT("remote"), PathToGitBinary, PathToProjectDir, Parameters, TArray<FString>(), InfoMessages, ErrorMessages);
}
// Check the new repository status to enable connection (branch, user e-mail)
GitSourceControl.GetProvider().CheckRepositoryStatus(PathToGitBinary);
if(GitSourceControl.GetProvider().IsAvailable())
{
// List of files to add to Source Control (.uproject, Config/, Content/, Source/ files and .gitignore/.gitattributes if any)
TArray<FString> ProjectFiles;
ProjectFiles.Add(FPaths::GetProjectFilePath());
ProjectFiles.Add(FPaths::ProjectConfigDir());
ProjectFiles.Add(FPaths::ProjectContentDir());
if (FPaths::DirectoryExists(FPaths::GameSourceDir()))
{
ProjectFiles.Add(FPaths::GameSourceDir());
}
if(bAutoCreateGitIgnore)
{
// 2.a. Create a standard ".gitignore" file with common patterns for a typical Blueprint & C++ project
const FString GitIgnoreFilename = FPaths::Combine(FPaths::ProjectDir(), TEXT(".gitignore"));
const FString GitIgnoreContent = TEXT("Binaries\nDerivedDataCache\nIntermediate\nSaved\n.vscode\n.vs\n*.VC.db\n*.opensdf\n*.opendb\n*.sdf\n*.sln\n*.suo\n*.xcodeproj\n*.xcworkspace\n*.log");
if(FFileHelper::SaveStringToFile(GitIgnoreContent, *GitIgnoreFilename, FFileHelper::EEncodingOptions::ForceUTF8WithoutBOM))
{
ProjectFiles.Add(GitIgnoreFilename);
}
}
if(bAutoCreateReadme)
{
// 2.b. Create a "README.md" file with a custom description
const FString ReadmeFilename = FPaths::Combine(FPaths::ProjectDir(), TEXT("README.md"));
if (FFileHelper::SaveStringToFile(ReadmeContent.ToString(), *ReadmeFilename, FFileHelper::EEncodingOptions::ForceUTF8WithoutBOM))
{
ProjectFiles.Add(ReadmeFilename);
}
}
if(bAutoCreateGitAttributes)
{
// 2.c. Synchronous (very quick) "lfs install" operation: needs only to be run once by user
GitSourceControlUtils::RunCommand(TEXT("lfs install"), PathToGitBinary, PathToProjectDir, TArray<FString>(), TArray<FString>(), InfoMessages, ErrorMessages);
// 2.d. Create a ".gitattributes" file to enable Git LFS (Large File System) for the whole "Content/" subdir
const FString GitAttributesFilename = FPaths::Combine(FPaths::ProjectDir(), TEXT(".gitattributes"));
FString GitAttributesContent;
if(GitSourceControl.AccessSettings().IsUsingGitLfsLocking())
{
// Git LFS 2.x File Locking mechanism
GitAttributesContent = TEXT("Content/** filter=lfs diff=lfs merge=lfs -text lockable\n");
}
else
{
GitAttributesContent = TEXT("Content/** filter=lfs diff=lfs merge=lfs -text\n");
}
if(FFileHelper::SaveStringToFile(GitAttributesContent, *GitAttributesFilename, FFileHelper::EEncodingOptions::ForceUTF8WithoutBOM))
{
ProjectFiles.Add(GitAttributesFilename);
}
}
// 3. Add files to Source Control: launch an asynchronous MarkForAdd operation
LaunchMarkForAddOperation(ProjectFiles);
// 4. The CheckIn will follow, at completion of the MarkForAdd operation
}
return FReply::Handled();
}
// Launch an asynchronous "MarkForAdd" operation and start an ongoing notification
void SGitSourceControlSettings::LaunchMarkForAddOperation(const TArray<FString>& InFiles)
{
FGitSourceControlModule& GitSourceControl = FModuleManager::GetModuleChecked<FGitSourceControlModule>("GitSourceControl");
TSharedRef<FMarkForAdd, ESPMode::ThreadSafe> MarkForAddOperation = ISourceControlOperation::Create<FMarkForAdd>();
ECommandResult::Type Result = GitSourceControl.GetProvider().Execute(MarkForAddOperation, InFiles, EConcurrency::Asynchronous, FSourceControlOperationComplete::CreateSP(this, &SGitSourceControlSettings::OnSourceControlOperationComplete));
if (Result == ECommandResult::Succeeded)
{
DisplayInProgressNotification(MarkForAddOperation);
}
else
{
DisplayFailureNotification(MarkForAddOperation);
}
}
// Launch an asynchronous "CheckIn" operation and start another ongoing notification
void SGitSourceControlSettings::LaunchCheckInOperation()
{
TSharedRef<FCheckIn, ESPMode::ThreadSafe> CheckInOperation = ISourceControlOperation::Create<FCheckIn>();
CheckInOperation->SetDescription(InitialCommitMessage);
FGitSourceControlModule& GitSourceControl = FModuleManager::GetModuleChecked<FGitSourceControlModule>("GitSourceControl");
ECommandResult::Type Result = GitSourceControl.GetProvider().Execute(CheckInOperation, TArray<FString>(), EConcurrency::Asynchronous, FSourceControlOperationComplete::CreateSP(this, &SGitSourceControlSettings::OnSourceControlOperationComplete));
if (Result == ECommandResult::Succeeded)
{
DisplayInProgressNotification(CheckInOperation);
}
else
{
DisplayFailureNotification(CheckInOperation);
}
}
/// Delegate called when a source control operation has completed: launch the next one and manage notifications
void SGitSourceControlSettings::OnSourceControlOperationComplete(const FSourceControlOperationRef& InOperation, ECommandResult::Type InResult)
{
RemoveInProgressNotification();
// Report result with a notification
if (InResult == ECommandResult::Succeeded)
{
DisplaySuccessNotification(InOperation);
}
else
{
DisplayFailureNotification(InOperation);
}
if ((InOperation->GetName() == "MarkForAdd") && (InResult == ECommandResult::Succeeded) && bAutoInitialCommit)
{
// 4. optional initial Asynchronous commit with custom message: launch a "CheckIn" Operation
LaunchCheckInOperation();
}
}
// Display an ongoing notification during the whole operation
void SGitSourceControlSettings::DisplayInProgressNotification(const FSourceControlOperationRef& InOperation)
{
FNotificationInfo Info(InOperation->GetInProgressString());
Info.bFireAndForget = false;
Info.ExpireDuration = 0.0f;
Info.FadeOutDuration = 1.0f;
OperationInProgressNotification = FSlateNotificationManager::Get().AddNotification(Info);
if (OperationInProgressNotification.IsValid())
{
OperationInProgressNotification.Pin()->SetCompletionState(SNotificationItem::CS_Pending);
}
}
// Remove the ongoing notification at the end of the operation
void SGitSourceControlSettings::RemoveInProgressNotification()
{
if (OperationInProgressNotification.IsValid())
{
OperationInProgressNotification.Pin()->ExpireAndFadeout();
OperationInProgressNotification.Reset();
}
}
// Display a temporary success notification at the end of the operation
void SGitSourceControlSettings::DisplaySuccessNotification(const FSourceControlOperationRef& InOperation)
{
const FText NotificationText = FText::Format(LOCTEXT("InitialCommit_Success", "{0} operation was successfull!"), FText::FromName(InOperation->GetName()));
FNotificationInfo Info(NotificationText);
Info.bUseSuccessFailIcons = true;
Info.Image = FEditorStyle::GetBrush(TEXT("NotificationList.SuccessImage"));
FSlateNotificationManager::Get().AddNotification(Info);
}
// Display a temporary failure notification at the end of the operation
void SGitSourceControlSettings::DisplayFailureNotification(const FSourceControlOperationRef& InOperation)
{
const FText NotificationText = FText::Format(LOCTEXT("InitialCommit_Failure", "Error: {0} operation failed!"), FText::FromName(InOperation->GetName()));
FNotificationInfo Info(NotificationText);
Info.ExpireDuration = 8.0f;
FSlateNotificationManager::Get().AddNotification(Info);
}
void SGitSourceControlSettings::OnCheckedCreateGitIgnore(ECheckBoxState NewCheckedState)
{
bAutoCreateGitIgnore = (NewCheckedState == ECheckBoxState::Checked);
}
void SGitSourceControlSettings::OnCheckedCreateReadme(ECheckBoxState NewCheckedState)
{
bAutoCreateReadme = (NewCheckedState == ECheckBoxState::Checked);
}
bool SGitSourceControlSettings::GetAutoCreateReadme() const
{
return bAutoCreateReadme;
}
void SGitSourceControlSettings::OnReadmeContentCommited(const FText& InText, ETextCommit::Type InCommitType)
{
ReadmeContent = InText;
}
FText SGitSourceControlSettings::GetReadmeContent() const
{
return ReadmeContent;
}
void SGitSourceControlSettings::OnCheckedCreateGitAttributes(ECheckBoxState NewCheckedState)
{
bAutoCreateGitAttributes = (NewCheckedState == ECheckBoxState::Checked);
}
void SGitSourceControlSettings::OnCheckedUseGitLfsLocking(ECheckBoxState NewCheckedState)
{
FGitSourceControlModule& GitSourceControl = FModuleManager::GetModuleChecked<FGitSourceControlModule>("GitSourceControl");
GitSourceControl.AccessSettings().SetUsingGitLfsLocking(NewCheckedState == ECheckBoxState::Checked);
GitSourceControl.AccessSettings().SaveSettings();
}
bool SGitSourceControlSettings::GetIsUsingGitLfsLocking() const
{
const FGitSourceControlModule& GitSourceControl = FModuleManager::GetModuleChecked<FGitSourceControlModule>("GitSourceControl");
return GitSourceControl.AccessSettings().IsUsingGitLfsLocking();
}
ECheckBoxState SGitSourceControlSettings::IsUsingGitLfsLocking() const
{
return (GetIsUsingGitLfsLocking() ? ECheckBoxState::Checked : ECheckBoxState::Unchecked);
}
void SGitSourceControlSettings::OnLfsUserNameCommited(const FText& InText, ETextCommit::Type InCommitType)
{
FGitSourceControlModule& GitSourceControl = FModuleManager::GetModuleChecked<FGitSourceControlModule>("GitSourceControl");
GitSourceControl.AccessSettings().SetLfsUserName(InText.ToString());
GitSourceControl.AccessSettings().SaveSettings();
}
FText SGitSourceControlSettings::GetLfsUserName() const
{
const FGitSourceControlModule& GitSourceControl = FModuleManager::GetModuleChecked<FGitSourceControlModule>("GitSourceControl");
return FText::FromString(GitSourceControl.AccessSettings().GetLfsUserName());
}
void SGitSourceControlSettings::OnCheckedInitialCommit(ECheckBoxState NewCheckedState)
{
bAutoInitialCommit = (NewCheckedState == ECheckBoxState::Checked);
}
bool SGitSourceControlSettings::GetAutoInitialCommit() const
{
return bAutoInitialCommit;
}
void SGitSourceControlSettings::OnInitialCommitMessageCommited(const FText& InText, ETextCommit::Type InCommitType)
{
InitialCommitMessage = InText;
}
FText SGitSourceControlSettings::GetInitialCommitMessage() const
{
return InitialCommitMessage;
}
void SGitSourceControlSettings::OnRemoteUrlCommited(const FText& InText, ETextCommit::Type InCommitType)
{
RemoteUrl = InText;
}
FText SGitSourceControlSettings::GetRemoteUrl() const
{
return RemoteUrl;
}
#undef LOCTEXT_NAMESPACE