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
 |