UpdateProjectCtrl.cpp 8.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260
  1. /*
  2. * Copyright (c) Contributors to the Open 3D Engine Project.
  3. * For complete copyright and license terms please see the LICENSE at the root of this distribution.
  4. *
  5. * SPDX-License-Identifier: Apache-2.0 OR MIT
  6. *
  7. */
  8. #include <GemCatalog/GemCatalogScreen.h>
  9. #include <ProjectManagerDefs.h>
  10. #include <PythonBindingsInterface.h>
  11. #include <ScreenHeaderWidget.h>
  12. #include <ScreensCtrl.h>
  13. #include <UpdateProjectCtrl.h>
  14. #include <UpdateProjectSettingsScreen.h>
  15. #include <ProjectUtils.h>
  16. #include <QDialogButtonBox>
  17. #include <QMessageBox>
  18. #include <QPushButton>
  19. #include <QStackedWidget>
  20. #include <QTabWidget>
  21. #include <QVBoxLayout>
  22. #include <QDir>
  23. namespace O3DE::ProjectManager
  24. {
  25. UpdateProjectCtrl::UpdateProjectCtrl(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(""));
  32. m_header->setSubTitle(tr("Edit Project Settings:"));
  33. connect(m_header->backButton(), &QPushButton::clicked, this, &UpdateProjectCtrl::HandleBackButton);
  34. vLayout->addWidget(m_header);
  35. m_updateSettingsScreen = new UpdateProjectSettingsScreen();
  36. m_gemCatalogScreen = new GemCatalogScreen();
  37. m_stack = new QStackedWidget(this);
  38. m_stack->setObjectName("body");
  39. m_stack->setSizePolicy(QSizePolicy(QSizePolicy::Preferred, QSizePolicy::Expanding));
  40. vLayout->addWidget(m_stack);
  41. QFrame* topBarFrameWidget = new QFrame(this);
  42. topBarFrameWidget->setObjectName("projectSettingsTopFrame");
  43. QHBoxLayout* topBarHLayout = new QHBoxLayout();
  44. topBarHLayout->setContentsMargins(0, 0, 0, 0);
  45. topBarFrameWidget->setLayout(topBarHLayout);
  46. QTabWidget* tabWidget = new QTabWidget();
  47. tabWidget->setObjectName("projectSettingsTab");
  48. tabWidget->tabBar()->setObjectName("projectSettingsTabBar");
  49. tabWidget->tabBar()->setFocusPolicy(Qt::TabFocus);
  50. tabWidget->addTab(m_updateSettingsScreen, tr("General"));
  51. QPushButton* gemsButton = new QPushButton(tr("Configure Gems"), this);
  52. topBarHLayout->addWidget(gemsButton);
  53. tabWidget->setCornerWidget(gemsButton);
  54. topBarHLayout->addWidget(tabWidget);
  55. m_stack->addWidget(topBarFrameWidget);
  56. m_stack->addWidget(m_gemCatalogScreen);
  57. QDialogButtonBox* backNextButtons = new QDialogButtonBox();
  58. backNextButtons->setObjectName("footer");
  59. vLayout->addWidget(backNextButtons);
  60. m_backButton = backNextButtons->addButton(tr("Back"), QDialogButtonBox::RejectRole);
  61. m_backButton->setProperty("secondary", true);
  62. m_nextButton = backNextButtons->addButton(tr("Next"), QDialogButtonBox::ApplyRole);
  63. connect(gemsButton, &QPushButton::clicked, this, &UpdateProjectCtrl::HandleGemsButton);
  64. connect(m_backButton, &QPushButton::clicked, this, &UpdateProjectCtrl::HandleBackButton);
  65. connect(m_nextButton, &QPushButton::clicked, this, &UpdateProjectCtrl::HandleNextButton);
  66. connect(reinterpret_cast<ScreensCtrl*>(parent), &ScreensCtrl::NotifyCurrentProject, this, &UpdateProjectCtrl::UpdateCurrentProject);
  67. Update();
  68. setLayout(vLayout);
  69. }
  70. ProjectManagerScreen UpdateProjectCtrl::GetScreenEnum()
  71. {
  72. return ProjectManagerScreen::UpdateProject;
  73. }
  74. // Called when pressing "Edit Project Settings..."
  75. void UpdateProjectCtrl::NotifyCurrentScreen()
  76. {
  77. m_stack->setCurrentIndex(ScreenOrder::Settings);
  78. Update();
  79. // Gather the available gems that will be shown in the gem catalog.
  80. m_gemCatalogScreen->ReinitForProject(m_projectInfo.m_path);
  81. }
  82. void UpdateProjectCtrl::HandleGemsButton()
  83. {
  84. if (UpdateProjectSettings(true))
  85. {
  86. m_stack->setCurrentWidget(m_gemCatalogScreen);
  87. Update();
  88. }
  89. }
  90. void UpdateProjectCtrl::HandleBackButton()
  91. {
  92. if (m_stack->currentIndex() > 0)
  93. {
  94. m_stack->setCurrentIndex(m_stack->currentIndex() - 1);
  95. Update();
  96. }
  97. else
  98. {
  99. if (UpdateProjectSettings(true))
  100. {
  101. emit GotoPreviousScreenRequest();
  102. }
  103. }
  104. }
  105. void UpdateProjectCtrl::HandleNextButton()
  106. {
  107. bool shouldRebuild = false;
  108. if (m_stack->currentIndex() == ScreenOrder::Settings && m_updateSettingsScreen)
  109. {
  110. if (!UpdateProjectSettings())
  111. {
  112. return;
  113. }
  114. }
  115. else if (m_stack->currentIndex() == ScreenOrder::Gems && m_gemCatalogScreen)
  116. {
  117. // Enable or disable the gems that got adjusted in the gem catalog and apply them to the given project.
  118. if (!m_gemCatalogScreen->EnableDisableGemsForProject(m_projectInfo.m_path))
  119. {
  120. QMessageBox::critical(this, tr("Failed to configure gems"), tr("Failed to configure gems for project."));
  121. return;
  122. }
  123. shouldRebuild = true;
  124. }
  125. if (shouldRebuild)
  126. {
  127. emit NotifyBuildProject(m_projectInfo);
  128. }
  129. emit ChangeScreenRequest(ProjectManagerScreen::Projects);
  130. }
  131. void UpdateProjectCtrl::UpdateCurrentProject(const QString& projectPath)
  132. {
  133. auto projectResult = PythonBindingsInterface::Get()->GetProject(projectPath);
  134. if (projectResult.IsSuccess())
  135. {
  136. m_projectInfo = projectResult.GetValue();
  137. }
  138. Update();
  139. UpdateSettingsScreen();
  140. }
  141. void UpdateProjectCtrl::Update()
  142. {
  143. if (m_stack->currentIndex() == ScreenOrder::Gems)
  144. {
  145. m_header->setTitle(QString(tr("Edit Project Settings: \"%1\"")).arg(m_projectInfo.GetProjectDisplayName()));
  146. m_header->setSubTitle(QString(tr("Configure Gems")));
  147. m_nextButton->setText(tr("Save"));
  148. }
  149. else
  150. {
  151. m_header->setTitle("");
  152. m_header->setSubTitle(QString(tr("Edit Project Settings: \"%1\"")).arg(m_projectInfo.GetProjectDisplayName()));
  153. m_nextButton->setText(tr("Save"));
  154. }
  155. }
  156. void UpdateProjectCtrl::UpdateSettingsScreen()
  157. {
  158. m_updateSettingsScreen->SetProjectInfo(m_projectInfo);
  159. }
  160. bool UpdateProjectCtrl::UpdateProjectSettings(bool shouldConfirm)
  161. {
  162. AZ_Assert(m_updateSettingsScreen, "Update settings screen is nullptr.")
  163. ProjectInfo newProjectSettings = m_updateSettingsScreen->GetProjectInfo();
  164. if (m_projectInfo != newProjectSettings)
  165. {
  166. if (shouldConfirm)
  167. {
  168. QMessageBox::StandardButton warningResult = QMessageBox::warning(
  169. this,
  170. QObject::tr("Unsaved Changes!"),
  171. QObject::tr("Would you like to save your changes to project settings?"),
  172. QMessageBox::No | QMessageBox::Yes
  173. );
  174. if (warningResult == QMessageBox::No)
  175. {
  176. return true;
  177. }
  178. }
  179. if (!m_updateSettingsScreen->Validate())
  180. {
  181. QMessageBox::critical(this, tr("Invalid project settings"), tr("Invalid project settings"));
  182. return false;
  183. }
  184. // Check if project path has changed and move it
  185. // Move project first to avoid trying to update settings at the new location before it has been moved there
  186. if (newProjectSettings.m_path != m_projectInfo.m_path)
  187. {
  188. if (!ProjectUtils::MoveProject(m_projectInfo.m_path, newProjectSettings.m_path, this))
  189. {
  190. QMessageBox::critical(this, tr("Project move failed"), tr("Failed to move project."));
  191. return false;
  192. }
  193. emit NotifyBuildProject(newProjectSettings);
  194. }
  195. // Update project if settings changed
  196. {
  197. auto result = PythonBindingsInterface::Get()->UpdateProject(newProjectSettings);
  198. if (!result.IsSuccess())
  199. {
  200. QMessageBox::critical(this, tr("Project update failed"), tr(result.GetError().c_str()));
  201. return false;
  202. }
  203. }
  204. if (!newProjectSettings.m_newPreviewImagePath.isEmpty())
  205. {
  206. if (!ProjectUtils::ReplaceProjectFile(
  207. QDir(newProjectSettings.m_path).filePath(newProjectSettings.m_iconPath), newProjectSettings.m_newPreviewImagePath))
  208. {
  209. QMessageBox::critical(this, tr("File replace failed"), tr("Failed to replace project preview image."));
  210. return false;
  211. }
  212. m_updateSettingsScreen->ResetProjectPreviewPath();
  213. }
  214. m_projectInfo = newProjectSettings;
  215. }
  216. return true;
  217. }
  218. } // namespace O3DE::ProjectManager