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
|