CreateProjectCtrl.cpp 9.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269
  1. /*
  2. * Copyright (c) Contributors to the Open 3D Engine Project. For complete copyright and license terms please see the LICENSE at the root of this distribution.
  3. *
  4. * SPDX-License-Identifier: Apache-2.0 OR MIT
  5. *
  6. */
  7. #include <CreateProjectCtrl.h>
  8. #include <ScreensCtrl.h>
  9. #include <PythonBindingsInterface.h>
  10. #include <NewProjectSettingsScreen.h>
  11. #include <ScreenHeaderWidget.h>
  12. #include <GemCatalog/GemModel.h>
  13. #include <GemCatalog/GemCatalogScreen.h>
  14. #include <ProjectUtils.h>
  15. #include <QDialogButtonBox>
  16. #include <QHBoxLayout>
  17. #include <QVBoxLayout>
  18. #include <QPushButton>
  19. #include <QMessageBox>
  20. #include <QStackedWidget>
  21. #include <QLabel>
  22. #include <QSizePolicy>
  23. namespace O3DE::ProjectManager
  24. {
  25. CreateProjectCtrl::CreateProjectCtrl(QWidget* parent)
  26. : ScreenWidget(parent)
  27. {
  28. QVBoxLayout* vLayout = new QVBoxLayout();
  29. vLayout->setContentsMargins(0,0,0,0);
  30. m_header = new ScreenHeader(this);
  31. m_header->setTitle(tr("Create a New Project"));
  32. m_header->setSubTitle(tr("Enter Project Details"));
  33. connect(m_header->backButton(), &QPushButton::clicked, this, &CreateProjectCtrl::HandleBackButton);
  34. vLayout->addWidget(m_header);
  35. m_stack = new QStackedWidget(this);
  36. m_stack->setObjectName("body");
  37. m_stack->setSizePolicy(QSizePolicy(QSizePolicy::Preferred,QSizePolicy::Expanding));
  38. m_newProjectSettingsScreen = new NewProjectSettingsScreen(this);
  39. m_stack->addWidget(m_newProjectSettingsScreen);
  40. m_gemCatalogScreen = new GemCatalogScreen(this);
  41. m_stack->addWidget(m_gemCatalogScreen);
  42. vLayout->addWidget(m_stack);
  43. // When there are multiple project templates present, we re-gather the gems when changing the selected the project template.
  44. connect(m_newProjectSettingsScreen, &NewProjectSettingsScreen::OnTemplateSelectionChanged, this, [=](int oldIndex, [[maybe_unused]] int newIndex)
  45. {
  46. const GemModel* gemModel = m_gemCatalogScreen->GetGemModel();
  47. const QVector<QModelIndex> toBeAdded = gemModel->GatherGemsToBeAdded();
  48. const QVector<QModelIndex> toBeRemoved = gemModel->GatherGemsToBeRemoved();
  49. if (!toBeAdded.isEmpty() || !toBeRemoved.isEmpty())
  50. {
  51. // In case the user enabled or disabled any gem and the current selection does not match the default from the
  52. // // project template anymore, we need to ask the user if they want to proceed as their modifications will be lost.
  53. const QString title = tr("Modifications will be lost");
  54. const QString text = tr("You selected a new project template after modifying the enabled gems.\n\n"
  55. "All modifications will be lost and the default from the new project template will be used.\n\n"
  56. "Do you want to proceed?");
  57. if (QMessageBox::warning(this, title, text, QMessageBox::Yes, QMessageBox::No) == QMessageBox::Yes)
  58. {
  59. // The users wants to proceed. Reinitialize based on the newly selected project template.
  60. ReinitGemCatalogForSelectedTemplate();
  61. }
  62. else
  63. {
  64. // Roll-back to the previously selected project template and
  65. // block signals so that we don't end up in this same callback again.
  66. m_newProjectSettingsScreen->SelectProjectTemplate(oldIndex, /*blockSignals=*/true);
  67. }
  68. }
  69. else
  70. {
  71. // In case the user did not enable or disable any gem and the currently enabled gems matches the previously selected
  72. // ones from the project template, we can just reinitialize based on the newly selected project template.
  73. ReinitGemCatalogForSelectedTemplate();
  74. }
  75. });
  76. QDialogButtonBox* buttons = new QDialogButtonBox();
  77. buttons->setObjectName("footer");
  78. vLayout->addWidget(buttons);
  79. #ifdef TEMPLATE_GEM_CONFIGURATION_ENABLED
  80. connect(m_newProjectSettingsScreen, &ScreenWidget::ChangeScreenRequest, this, &CreateProjectCtrl::OnChangeScreenRequest);
  81. m_secondaryButton = buttons->addButton(tr("Back"), QDialogButtonBox::RejectRole);
  82. m_secondaryButton->setProperty("secondary", true);
  83. m_secondaryButton->setVisible(false);
  84. connect(m_secondaryButton, &QPushButton::clicked, this, &CreateProjectCtrl::HandleSecondaryButton);
  85. Update();
  86. #endif // TEMPLATE_GEM_CONFIGURATION_ENABLED
  87. m_primaryButton = buttons->addButton(tr("Create Project"), QDialogButtonBox::ApplyRole);
  88. connect(m_primaryButton, &QPushButton::clicked, this, &CreateProjectCtrl::HandlePrimaryButton);
  89. setLayout(vLayout);
  90. }
  91. ProjectManagerScreen CreateProjectCtrl::GetScreenEnum()
  92. {
  93. return ProjectManagerScreen::CreateProject;
  94. }
  95. // Called when pressing "Create New Project"
  96. void CreateProjectCtrl::NotifyCurrentScreen()
  97. {
  98. ScreenWidget* currentScreen = reinterpret_cast<ScreenWidget*>(m_stack->currentWidget());
  99. if (currentScreen)
  100. {
  101. currentScreen->NotifyCurrentScreen();
  102. }
  103. // Gather the enabled gems from the default project template when starting the create new project workflow.
  104. ReinitGemCatalogForSelectedTemplate();
  105. }
  106. void CreateProjectCtrl::HandleBackButton()
  107. {
  108. if (m_stack->currentIndex() > 0)
  109. {
  110. #ifdef TEMPLATE_GEM_CONFIGURATION_ENABLED
  111. PreviousScreen();
  112. #endif // TEMPLATE_GEM_CONFIGURATION_ENABLED
  113. }
  114. else
  115. {
  116. emit GotoPreviousScreenRequest();
  117. }
  118. }
  119. #ifdef TEMPLATE_GEM_CONFIGURATION_ENABLED
  120. void CreateProjectCtrl::HandleSecondaryButton()
  121. {
  122. if (m_stack->currentIndex() > 0)
  123. {
  124. // return to Project Settings page
  125. PreviousScreen();
  126. }
  127. else
  128. {
  129. // Configure Gems
  130. NextScreen();
  131. }
  132. }
  133. void CreateProjectCtrl::Update()
  134. {
  135. if (m_stack->currentWidget() == m_gemCatalogScreen)
  136. {
  137. m_header->setSubTitle(tr("Configure project with Gems"));
  138. m_secondaryButton->setVisible(false);
  139. }
  140. else
  141. {
  142. m_header->setSubTitle(tr("Enter Project Details"));
  143. m_secondaryButton->setVisible(true);
  144. m_secondaryButton->setText(tr("Configure Gems"));
  145. }
  146. }
  147. void CreateProjectCtrl::OnChangeScreenRequest(ProjectManagerScreen screen)
  148. {
  149. if (screen == ProjectManagerScreen::GemCatalog)
  150. {
  151. HandleSecondaryButton();
  152. }
  153. else
  154. {
  155. emit ChangeScreenRequest(screen);
  156. }
  157. }
  158. void CreateProjectCtrl::NextScreen()
  159. {
  160. if (m_stack->currentIndex() < m_stack->count())
  161. {
  162. if(CurrentScreenIsValid())
  163. {
  164. m_stack->setCurrentIndex(m_stack->currentIndex() + 1);
  165. Update();
  166. }
  167. else
  168. {
  169. QMessageBox::warning(this, tr("Invalid project settings"), tr("Please correct the indicated project settings and try again."));
  170. }
  171. }
  172. }
  173. void CreateProjectCtrl::PreviousScreen()
  174. {
  175. // we don't require the current screen to be valid when moving back
  176. if (m_stack->currentIndex() > 0)
  177. {
  178. m_stack->setCurrentIndex(m_stack->currentIndex() - 1);
  179. Update();
  180. }
  181. }
  182. #endif // TEMPLATE_GEM_CONFIGURATION_ENABLED
  183. void CreateProjectCtrl::HandlePrimaryButton()
  184. {
  185. CreateProject();
  186. }
  187. bool CreateProjectCtrl::CurrentScreenIsValid()
  188. {
  189. if (m_stack->currentWidget() == m_newProjectSettingsScreen)
  190. {
  191. return m_newProjectSettingsScreen->Validate();
  192. }
  193. return true;
  194. }
  195. void CreateProjectCtrl::CreateProject()
  196. {
  197. if (ProjectUtils::FindSupportedCompiler(this))
  198. {
  199. if (m_newProjectSettingsScreen->Validate())
  200. {
  201. ProjectInfo projectInfo = m_newProjectSettingsScreen->GetProjectInfo();
  202. QString projectTemplatePath = m_newProjectSettingsScreen->GetProjectTemplatePath();
  203. auto result = PythonBindingsInterface::Get()->CreateProject(projectTemplatePath, projectInfo);
  204. if (result.IsSuccess())
  205. {
  206. // automatically register the project
  207. PythonBindingsInterface::Get()->AddProject(projectInfo.m_path);
  208. #ifdef TEMPLATE_GEM_CONFIGURATION_ENABLED
  209. if (!m_gemCatalogScreen->EnableDisableGemsForProject(projectInfo.m_path))
  210. {
  211. QMessageBox::critical(this, tr("Failed to configure gems"), tr("Failed to configure gems for template."));
  212. return;
  213. }
  214. #endif // TEMPLATE_GEM_CONFIGURATION_ENABLED
  215. projectInfo.m_needsBuild = true;
  216. emit NotifyBuildProject(projectInfo);
  217. emit ChangeScreenRequest(ProjectManagerScreen::Projects);
  218. }
  219. else
  220. {
  221. QMessageBox::critical(this, tr("Project creation failed"), tr("Failed to create project."));
  222. }
  223. }
  224. else
  225. {
  226. QMessageBox::warning(
  227. this, tr("Invalid project settings"), tr("Please correct the indicated project settings and try again."));
  228. }
  229. }
  230. }
  231. void CreateProjectCtrl::ReinitGemCatalogForSelectedTemplate()
  232. {
  233. const QString projectTemplatePath = m_newProjectSettingsScreen->GetProjectTemplatePath();
  234. m_gemCatalogScreen->ReinitForProject(projectTemplatePath + "/Template", /*isNewProject=*/true);
  235. }
  236. } // namespace O3DE::ProjectManager