ProjectUtils.cpp 7.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251
  1. /*
  2. * All or portions of this file Copyright (c) Amazon.com, Inc. or its affiliates or
  3. * its licensors.
  4. *
  5. * For complete copyright and license terms please see the LICENSE at the root of this
  6. * distribution (the "License"). All use of this software is governed by the License,
  7. * or, if provided, by the license below or the license accompanying this file. Do not
  8. * remove or modify any license notices. This file is distributed on an "AS IS" BASIS,
  9. * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  10. *
  11. */
  12. #include <ProjectUtils.h>
  13. #include <PythonBindingsInterface.h>
  14. #include <QFileDialog>
  15. #include <QDir>
  16. #include <QMessageBox>
  17. #include <QFileInfo>
  18. #include <QProcess>
  19. #include <QProcessEnvironment>
  20. namespace O3DE::ProjectManager
  21. {
  22. namespace ProjectUtils
  23. {
  24. static bool WarnDirectoryOverwrite(const QString& path, QWidget* parent)
  25. {
  26. if (!QDir(path).isEmpty())
  27. {
  28. QMessageBox::StandardButton warningResult = QMessageBox::warning(
  29. parent,
  30. QObject::tr("Overwrite Directory"),
  31. QObject::tr("Directory is not empty! Are you sure you want to overwrite it?"),
  32. QMessageBox::No | QMessageBox::Yes
  33. );
  34. if (warningResult != QMessageBox::Yes)
  35. {
  36. return false;
  37. }
  38. }
  39. return true;
  40. }
  41. static bool IsDirectoryDescedent(const QString& possibleAncestorPath, const QString& possibleDecedentPath)
  42. {
  43. QDir ancestor(possibleAncestorPath);
  44. QDir descendent(possibleDecedentPath);
  45. do
  46. {
  47. if (ancestor == descendent)
  48. {
  49. return false;
  50. }
  51. descendent.cdUp();
  52. }
  53. while (!descendent.isRoot());
  54. return true;
  55. }
  56. static bool CopyDirectory(const QString& origPath, const QString& newPath)
  57. {
  58. QDir original(origPath);
  59. if (!original.exists())
  60. {
  61. return false;
  62. }
  63. for (QString directory : original.entryList(QDir::Dirs | QDir::NoDotAndDotDot))
  64. {
  65. QString newDirectoryPath = newPath + QDir::separator() + directory;
  66. original.mkpath(newDirectoryPath);
  67. if (!CopyDirectory(origPath + QDir::separator() + directory, newDirectoryPath))
  68. {
  69. return false;
  70. }
  71. }
  72. for (QString file : original.entryList(QDir::Files))
  73. {
  74. if (!QFile::copy(origPath + QDir::separator() + file, newPath + QDir::separator() + file))
  75. return false;
  76. }
  77. return true;
  78. }
  79. bool AddProjectDialog(QWidget* parent)
  80. {
  81. QString path = QDir::toNativeSeparators(QFileDialog::getExistingDirectory(parent, QObject::tr("Select Project Directory")));
  82. if (!path.isEmpty())
  83. {
  84. return RegisterProject(path);
  85. }
  86. return false;
  87. }
  88. bool RegisterProject(const QString& path)
  89. {
  90. return PythonBindingsInterface::Get()->AddProject(path);
  91. }
  92. bool UnregisterProject(const QString& path)
  93. {
  94. return PythonBindingsInterface::Get()->RemoveProject(path);
  95. }
  96. bool CopyProjectDialog(const QString& origPath, QWidget* parent)
  97. {
  98. bool copyResult = false;
  99. QDir parentOrigDir(origPath);
  100. parentOrigDir.cdUp();
  101. QString newPath = QDir::toNativeSeparators(
  102. QFileDialog::getExistingDirectory(parent, QObject::tr("Select New Project Directory"), parentOrigDir.path()));
  103. if (!newPath.isEmpty())
  104. {
  105. if (!WarnDirectoryOverwrite(newPath, parent))
  106. {
  107. return false;
  108. }
  109. // TODO: Block UX and Notify User they need to wait
  110. copyResult = CopyProject(origPath, newPath);
  111. }
  112. return copyResult;
  113. }
  114. bool CopyProject(const QString& origPath, const QString& newPath)
  115. {
  116. // Disallow copying from or into subdirectory
  117. if (!IsDirectoryDescedent(origPath, newPath) || !IsDirectoryDescedent(newPath, origPath))
  118. {
  119. return false;
  120. }
  121. if (!CopyDirectory(origPath, newPath))
  122. {
  123. // Cleanup whatever mess was made
  124. DeleteProjectFiles(newPath, true);
  125. return false;
  126. }
  127. if (!RegisterProject(newPath))
  128. {
  129. DeleteProjectFiles(newPath, true);
  130. }
  131. return true;
  132. }
  133. bool DeleteProjectFiles(const QString& path, bool force)
  134. {
  135. QDir projectDirectory(path);
  136. if (projectDirectory.exists())
  137. {
  138. // Check if there is an actual project hereor just force it
  139. if (force || PythonBindingsInterface::Get()->GetProject(path).IsSuccess())
  140. {
  141. return projectDirectory.removeRecursively();
  142. }
  143. }
  144. return false;
  145. }
  146. bool MoveProject(const QString& origPath, const QString& newPath, QWidget* parent)
  147. {
  148. if (!WarnDirectoryOverwrite(newPath, parent) || !UnregisterProject(origPath))
  149. {
  150. return false;
  151. }
  152. QDir directory;
  153. if (directory.rename(origPath, newPath))
  154. {
  155. return directory.rename(origPath, newPath);
  156. }
  157. if (!RegisterProject(newPath))
  158. {
  159. return false;
  160. }
  161. return true;
  162. }
  163. static bool IsVS2019Installed_internal()
  164. {
  165. QProcessEnvironment environment = QProcessEnvironment::systemEnvironment();
  166. QString programFilesPath = environment.value("ProgramFiles(x86)");
  167. QString vsWherePath = programFilesPath + "\\Microsoft Visual Studio\\Installer\\vswhere.exe";
  168. QFileInfo vsWhereFile(vsWherePath);
  169. if (vsWhereFile.exists() && vsWhereFile.isFile())
  170. {
  171. QProcess vsWhereProcess;
  172. vsWhereProcess.setProcessChannelMode(QProcess::MergedChannels);
  173. vsWhereProcess.start(
  174. vsWherePath,
  175. QStringList{ "-version", "16.0", "-latest", "-requires", "Microsoft.VisualStudio.Component.VC.Tools.x86.x64",
  176. "-property", "isComplete" });
  177. if (!vsWhereProcess.waitForStarted())
  178. {
  179. return false;
  180. }
  181. while (vsWhereProcess.waitForReadyRead())
  182. {
  183. }
  184. QString vsWhereOutput(vsWhereProcess.readAllStandardOutput());
  185. if (vsWhereOutput.startsWith("1"))
  186. {
  187. return true;
  188. }
  189. }
  190. return false;
  191. }
  192. bool IsVS2019Installed()
  193. {
  194. static bool vs2019Installed = IsVS2019Installed_internal();
  195. return vs2019Installed;
  196. }
  197. ProjectManagerScreen GetProjectManagerScreen(const QString& screen)
  198. {
  199. auto iter = s_ProjectManagerStringNames.find(screen);
  200. if (iter != s_ProjectManagerStringNames.end())
  201. {
  202. return iter.value();
  203. }
  204. return ProjectManagerScreen::Invalid;
  205. }
  206. } // namespace ProjectUtils
  207. } // namespace O3DE::ProjectManager