308 lines
		
	
	
		
			9.8 KiB
		
	
	
	
		
			C++
		
	
	
	
	
	
			
		
		
	
	
			308 lines
		
	
	
		
			9.8 KiB
		
	
	
	
		
			C++
		
	
	
	
	
	
#include "CSNewProjectWizard.h"
 | 
						|
 | 
						|
#include "CSManager.h"
 | 
						|
#include "DesktopPlatformModule.h"
 | 
						|
#include "IDesktopPlatform.h"
 | 
						|
#include "Interfaces/IPluginManager.h"
 | 
						|
#include "Runtime/AppFramework/Public/Widgets/Workflow/SWizard.h"
 | 
						|
#include "UnrealSharpEditor/UnrealSharpEditor.h"
 | 
						|
#include "UnrealSharpProcHelper/CSProcHelper.h"
 | 
						|
 | 
						|
#define LOCTEXT_NAMESPACE "UnrealSharpEditor"
 | 
						|
 | 
						|
void SCSNewProjectDialog::Construct(const FArguments& InArgs)
 | 
						|
{
 | 
						|
    static FName ProjectDestination(TEXT("<ProjectDestination>"));
 | 
						|
	const FString ScriptPath = FPaths::ConvertRelativePathToFull(FCSProcHelper::GetScriptFolderDirectory());
 | 
						|
 | 
						|
	FText ProjectDestinationName = FText::FromString(FString::Printf(TEXT("%s (This Project)"), FApp::GetProjectName()));
 | 
						|
    ProjectDestinations.Add(MakeShared<FCSProjectDestination>(ProjectDestination, ProjectDestinationName, FApp::GetProjectName(), ScriptPath, 0));
 | 
						|
	
 | 
						|
    IPluginManager& PluginManager = IPluginManager::Get();
 | 
						|
    TArray<TSharedRef<IPlugin>> EnabledPlugins = PluginManager.GetEnabledPlugins();
 | 
						|
 | 
						|
    for (const TSharedRef<IPlugin>& Plugin : EnabledPlugins)
 | 
						|
    {
 | 
						|
        const FString PluginFilePath = FPaths::ConvertRelativePathToFull(Plugin->GetBaseDir());
 | 
						|
        if (!FPaths::IsUnderDirectory(PluginFilePath, FCSProcHelper::GetPluginsDirectory()) || Plugin->GetName() == UE_PLUGIN_NAME)
 | 
						|
        {
 | 
						|
            continue;
 | 
						|
        }
 | 
						|
    	
 | 
						|
        FString ScriptDirectory = PluginFilePath / "Script";
 | 
						|
        ProjectDestinations.Add(MakeShared<FCSProjectDestination>(FName(Plugin->GetName()),
 | 
						|
            FText::FromString(Plugin->GetFriendlyName()), Plugin->GetName(), ScriptDirectory, ProjectDestinations.Num(), Plugin));
 | 
						|
    }
 | 
						|
    SelectedProjectDestinationIndex = 0;
 | 
						|
 | 
						|
	ChildSlot
 | 
						|
	[
 | 
						|
		SNew(SWizard)
 | 
						|
		.ShowPageList(false)
 | 
						|
		.FinishButtonText(LOCTEXT("CreateProject", "Create C# Project"))
 | 
						|
		.FinishButtonToolTip(LOCTEXT("CreateProjectTooltip", "Create a new C# project with the specified settings"))
 | 
						|
		.OnCanceled(this, &SCSNewProjectDialog::OnCancel)
 | 
						|
		.OnFinished(this, &SCSNewProjectDialog::OnFinish)
 | 
						|
		.CanFinish(this, &SCSNewProjectDialog::CanFinish)
 | 
						|
		+ SWizard::Page()
 | 
						|
		[
 | 
						|
			SNew(SOverlay)
 | 
						|
			+ SOverlay::Slot()
 | 
						|
			.HAlign(HAlign_Center)
 | 
						|
			.VAlign(VAlign_Center)
 | 
						|
			[
 | 
						|
				SNew(SVerticalBox)
 | 
						|
				+ SVerticalBox::Slot()
 | 
						|
				.Padding(0, 0, 0, 10)
 | 
						|
				[
 | 
						|
					SNew(SHorizontalBox)
 | 
						|
					+ SHorizontalBox::Slot()
 | 
						|
					.AutoWidth()
 | 
						|
					.VAlign(VAlign_Center)
 | 
						|
					.Padding(0, 0, 10, 0)
 | 
						|
					[
 | 
						|
						SNew(STextBlock)
 | 
						|
						.Text(LOCTEXT("NewProjectName", "Name"))
 | 
						|
					]
 | 
						|
					+ SHorizontalBox::Slot()
 | 
						|
					.FillWidth(1)
 | 
						|
					[
 | 
						|
						SAssignNew(NameTextBox, SEditableTextBox)
 | 
						|
					]
 | 
						|
				]
 | 
						|
				+ SVerticalBox::Slot()
 | 
						|
				.Padding(0, 0, 0, 10)
 | 
						|
				[
 | 
						|
					SNew(SHorizontalBox)
 | 
						|
					+ SHorizontalBox::Slot()
 | 
						|
					.AutoWidth()
 | 
						|
					.VAlign(VAlign_Center)
 | 
						|
					.Padding(0, 0, 10, 0)
 | 
						|
					[
 | 
						|
						SNew(STextBlock)
 | 
						|
						.Text(LOCTEXT("NewProjectOwner", "Owner"))
 | 
						|
					]
 | 
						|
					+ SHorizontalBox::Slot()
 | 
						|
					.FillWidth(1)
 | 
						|
					[
 | 
						|
						SAssignNew(ProjectDestinationComboBox, SComboBox<TSharedRef<FCSProjectDestination>>)
 | 
						|
					    .OptionsSource(&ProjectDestinations)
 | 
						|
					    .InitiallySelectedItem(ProjectDestinations[SelectedProjectDestinationIndex])
 | 
						|
					    .OnSelectionChanged(this, &SCSNewProjectDialog::OnProjectDestinationChanged)
 | 
						|
					    .OnGenerateWidget_Static(&SCSNewProjectDialog::OnGenerateProjectDestinationWidget)
 | 
						|
					    .Content()
 | 
						|
                        [
 | 
						|
                            SNew(STextBlock).Text_Lambda([this]
 | 
						|
                            {
 | 
						|
                                if (SelectedProjectDestinationIndex == INDEX_NONE)
 | 
						|
                                {
 | 
						|
                                    return FText();
 | 
						|
                                }
 | 
						|
 | 
						|
                                return ProjectDestinations[SelectedProjectDestinationIndex]->GetDisplayName();
 | 
						|
                            })
 | 
						|
                        ]
 | 
						|
					]
 | 
						|
				]
 | 
						|
			    + SVerticalBox::Slot()
 | 
						|
                .Padding(0, 0, 0, 10)
 | 
						|
                [
 | 
						|
                    SNew(SHorizontalBox)
 | 
						|
                    + SHorizontalBox::Slot()
 | 
						|
                    .AutoWidth()
 | 
						|
                    .VAlign(VAlign_Center)
 | 
						|
                    .Padding(0, 0, 10, 0)
 | 
						|
                    [
 | 
						|
                        SNew(STextBlock)
 | 
						|
                        .Text(LOCTEXT("NewProjectLocation", "Location"))
 | 
						|
                    ]
 | 
						|
                    + SHorizontalBox::Slot()
 | 
						|
                    .FillWidth(1)
 | 
						|
                    [
 | 
						|
                        SAssignNew(PathTextBox, SEditableTextBox)
 | 
						|
                        .Text(FText::FromString(ScriptPath))
 | 
						|
                    ]
 | 
						|
                    + SHorizontalBox::Slot()
 | 
						|
                    .AutoWidth()
 | 
						|
                    [
 | 
						|
                        SNew(SButton)
 | 
						|
                        .VAlign(VAlign_Center)
 | 
						|
                        .ButtonStyle(FAppStyle::Get(), "SimpleButton")
 | 
						|
                        .OnClicked(this, &SCSNewProjectDialog::OnExplorerButtonClicked)
 | 
						|
                        [
 | 
						|
                            SNew(SImage)
 | 
						|
                            .Image(FAppStyle::Get().GetBrush("Icons.FolderClosed"))
 | 
						|
                            .ColorAndOpacity(FSlateColor::UseForeground())
 | 
						|
                        ]
 | 
						|
                    ]
 | 
						|
                ]
 | 
						|
			]
 | 
						|
		]
 | 
						|
	];
 | 
						|
 | 
						|
	OnProjectDestinationChanged(ProjectDestinations[SelectedProjectDestinationIndex], ESelectInfo::Direct);
 | 
						|
}
 | 
						|
 | 
						|
void SCSNewProjectDialog::OnProjectDestinationChanged(TSharedPtr<FCSProjectDestination> NewProjectDestination, ESelectInfo::Type)
 | 
						|
{
 | 
						|
    if (NewProjectDestination == nullptr)
 | 
						|
    {
 | 
						|
        SelectedProjectDestinationIndex = INDEX_NONE;
 | 
						|
        return;
 | 
						|
    }
 | 
						|
 | 
						|
    SelectedProjectDestinationIndex = NewProjectDestination->GetIndex();
 | 
						|
    PathTextBox->SetText(FText::FromString(NewProjectDestination->GetPath()));
 | 
						|
	
 | 
						|
	FString ManagedName = TEXT("Managed") + NewProjectDestination->GetName();
 | 
						|
	NameTextBox->SetText(FText::FromString(ManagedName));
 | 
						|
}
 | 
						|
 | 
						|
TSharedRef<SWidget> SCSNewProjectDialog::OnGenerateProjectDestinationWidget(TSharedRef<FCSProjectDestination> Destination)
 | 
						|
{
 | 
						|
    return SNew(STextBlock)
 | 
						|
        .Text(Destination->GetDisplayName());
 | 
						|
}
 | 
						|
 | 
						|
void SCSNewProjectDialog::OnPathSelected(const FString& NewPath)
 | 
						|
{
 | 
						|
	if (NewPath.IsEmpty())
 | 
						|
	{
 | 
						|
		return;
 | 
						|
	}
 | 
						|
 | 
						|
	PathTextBox->SetText(FText::FromString(NewPath));
 | 
						|
}
 | 
						|
 | 
						|
FReply SCSNewProjectDialog::OnExplorerButtonClicked()
 | 
						|
{
 | 
						|
	IDesktopPlatform* DesktopPlatform = FDesktopPlatformModule::Get();
 | 
						|
 | 
						|
	if (!DesktopPlatform)
 | 
						|
	{
 | 
						|
		return FReply::Handled();
 | 
						|
	}
 | 
						|
 | 
						|
	TSharedPtr<SWindow> ParentWindow = FSlateApplication::Get().FindWidgetWindow(AsShared());
 | 
						|
	void* ParentWindowWindowHandle = ParentWindow.IsValid() ? ParentWindow->GetNativeWindow()->GetOSWindowHandle() : nullptr;
 | 
						|
 | 
						|
	FString FolderName;
 | 
						|
	const FString Title = TEXT("Choose a location for new project");
 | 
						|
	if (DesktopPlatform->OpenDirectoryDialog(ParentWindowWindowHandle, Title,FCSProcHelper::GetScriptFolderDirectory(), FolderName))
 | 
						|
	{
 | 
						|
		if (!FolderName.EndsWith(TEXT("/")) )
 | 
						|
		{
 | 
						|
			FolderName += TEXT("/");
 | 
						|
		}
 | 
						|
	}
 | 
						|
 | 
						|
	if (FolderName.IsEmpty())
 | 
						|
	{
 | 
						|
		return FReply::Handled();
 | 
						|
	}
 | 
						|
 | 
						|
	PathTextBox->SetText(FText::FromString(FolderName));
 | 
						|
 | 
						|
	return FReply::Handled();
 | 
						|
}
 | 
						|
 | 
						|
void SCSNewProjectDialog::OnCancel()
 | 
						|
{
 | 
						|
	CloseWindow();
 | 
						|
}
 | 
						|
 | 
						|
void SCSNewProjectDialog::OnFinish()
 | 
						|
{
 | 
						|
	TMap<FString, FString> Arguments;
 | 
						|
	FString ModuleName = NameTextBox->GetText().ToString();
 | 
						|
	FString ProjectParentFolder = PathTextBox->GetText().ToString();
 | 
						|
 | 
						|
	FString ProjectRoot;
 | 
						|
	FString GlueProjectLocation;
 | 
						|
	FString GlueProjectName;
 | 
						|
 | 
						|
	auto MakeGlueNameAndLocation = [](FString& GlueLocation, FString& GlueName, const FString& PluginName, const FString& CsProjFolder)
 | 
						|
	{
 | 
						|
		GlueName = FString::Printf(TEXT("%s.Glue"), *PluginName);
 | 
						|
		GlueLocation = FPaths::Combine(CsProjFolder, FString::Printf(TEXT("%s.csproj"), *GlueName));
 | 
						|
	};
 | 
						|
	
 | 
						|
    if (ProjectDestinations.IsValidIndex(SelectedProjectDestinationIndex) && SelectedProjectDestinationIndex > 0)
 | 
						|
    {
 | 
						|
    	const TSharedRef<FCSProjectDestination>& Destination = ProjectDestinations[SelectedProjectDestinationIndex];
 | 
						|
    	const TSharedPtr<IPlugin>& Plugin = Destination->GetPlugin();
 | 
						|
 | 
						|
    	ProjectRoot = Plugin->GetBaseDir();
 | 
						|
    	MakeGlueNameAndLocation(GlueProjectLocation, GlueProjectName, Plugin->GetName(), FPaths::Combine(Destination->GetPath(), GlueProjectName));
 | 
						|
    }
 | 
						|
    else
 | 
						|
    {
 | 
						|
    	ProjectRoot = FPaths::ProjectDir();
 | 
						|
    	MakeGlueNameAndLocation(GlueProjectLocation, GlueProjectName, FApp::GetProjectName(), FCSProcHelper::GetProjectGlueFolderPath());
 | 
						|
    }
 | 
						|
 | 
						|
	if (!FPaths::FileExists(GlueProjectLocation))
 | 
						|
	{
 | 
						|
		Arguments.Add(TEXT("SkipIncludeProjectGlue"), TEXT("true"));
 | 
						|
	}
 | 
						|
 | 
						|
	Arguments.Add(TEXT("GlueProjectName"), GlueProjectName);
 | 
						|
	
 | 
						|
	FUnrealSharpEditorModule::Get().AddNewProject(ModuleName, ProjectParentFolder, ProjectRoot, Arguments);
 | 
						|
	CloseWindow();
 | 
						|
}
 | 
						|
 | 
						|
bool SCSNewProjectDialog::CanFinish() const
 | 
						|
{
 | 
						|
	FString Name = NameTextBox->GetText().ToString();
 | 
						|
	FString Path = PathTextBox->GetText().ToString();
 | 
						|
	FString Filename = Name + ".csproj";
 | 
						|
	FString AbsolutePath = Path / Filename;
 | 
						|
 | 
						|
	// Path can't be empty, name can't be empty, and path must contain the script path
 | 
						|
	if (Path.IsEmpty() || Name.IsEmpty() || SelectedProjectDestinationIndex == INDEX_NONE
 | 
						|
	    || !Path.Contains(ProjectDestinations[SelectedProjectDestinationIndex]->GetPath()))
 | 
						|
	{
 | 
						|
		return false;
 | 
						|
	}
 | 
						|
 | 
						|
	// Name can't contain spaces
 | 
						|
	if (Name.Contains(TEXT(" ")))
 | 
						|
	{
 | 
						|
		return false;
 | 
						|
	}
 | 
						|
 | 
						|
	// Path must be a valid directory
 | 
						|
	if (FPaths::DirectoryExists(Path / Name))
 | 
						|
	{
 | 
						|
		return false;
 | 
						|
	}
 | 
						|
 | 
						|
	// File must not already exist
 | 
						|
	IFileManager& FileManager = IFileManager::Get();
 | 
						|
	TArray<FString> AssemblyPaths;
 | 
						|
	FileManager.FindFiles(AssemblyPaths, *Path, TEXT(".csproj"));
 | 
						|
 | 
						|
	for (const FString& AssemblyPath : AssemblyPaths)
 | 
						|
	{
 | 
						|
		FString ProjectName = FPaths::GetBaseFilename(AssemblyPath);
 | 
						|
		if (ProjectName == Name)
 | 
						|
		{
 | 
						|
			return false;
 | 
						|
		}
 | 
						|
	}
 | 
						|
 | 
						|
	return true;
 | 
						|
}
 | 
						|
 | 
						|
void SCSNewProjectDialog::CloseWindow()
 | 
						|
{
 | 
						|
	TSharedPtr<SWindow> ContainingWindow = FSlateApplication::Get().FindWidgetWindow(AsShared());
 | 
						|
	if (ContainingWindow.IsValid())
 | 
						|
	{
 | 
						|
		ContainingWindow->RequestDestroyWindow();
 | 
						|
	}
 | 
						|
}
 | 
						|
 | 
						|
#undef LOCTEXT_NAMESPACE
 |