SaveDirtyFilesCallbacks.cpp 19 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581
  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 <EMotionFX/Source/ActorManager.h>
  9. #include <EMotionFX/Source/AnimGraphManager.h>
  10. #include <EMotionFX/Source/MotionManager.h>
  11. #include <EMotionFX/Tools/EMotionStudio/EMStudioSDK/Source/EMStudioManager.h>
  12. #include <EMotionFX/Tools/EMotionStudio/EMStudioSDK/Source/FileManager.h>
  13. #include <EMotionFX/Tools/EMotionStudio/EMStudioSDK/Source/MainWindow.h>
  14. #include <Editor/SaveDirtyFilesCallbacks.h>
  15. #include <QApplication>
  16. #include <QMessageBox>
  17. namespace EMStudio
  18. {
  19. void SaveDirtyActorFilesCallback::GetDirtyFileNames(
  20. AZStd::vector<AZStd::string>* outFileNames, AZStd::vector<ObjectPointer>* outObjects)
  21. {
  22. const size_t numLeaderActors = EMotionFX::GetActorManager().GetNumActors();
  23. for (size_t i = 0; i < numLeaderActors; ++i)
  24. {
  25. EMotionFX::Actor* actor = EMotionFX::GetActorManager().GetActor(i);
  26. if (actor->GetDirtyFlag() &&
  27. !actor->GetIsUsedForVisualization())
  28. {
  29. outFileNames->push_back(actor->GetFileName());
  30. ObjectPointer objPointer;
  31. objPointer.m_actor = actor;
  32. outObjects->push_back(objPointer);
  33. }
  34. }
  35. }
  36. int SaveDirtyActorFilesCallback::SaveDirtyFiles(
  37. [[maybe_unused]] const AZStd::vector<AZStd::string>& filenamesToSave,
  38. const AZStd::vector<ObjectPointer>& objects,
  39. MCore::CommandGroup* commandGroup)
  40. {
  41. for (const ObjectPointer& objPointer : objects)
  42. {
  43. if (!objPointer.m_actor)
  44. {
  45. continue;
  46. }
  47. EMotionFX::Actor* actor = objPointer.m_actor;
  48. if (SaveDirtyActor(actor, commandGroup, false) == DirtyFileManager::CANCELED)
  49. {
  50. return DirtyFileManager::CANCELED;
  51. }
  52. }
  53. return DirtyFileManager::FINISHED;
  54. }
  55. int SaveDirtyActorFilesCallback::SaveDirtyActor(
  56. EMotionFX::Actor* actor, [[maybe_unused]] MCore::CommandGroup* commandGroup, bool askBeforeSaving, bool showCancelButton)
  57. {
  58. // only process changed files
  59. if (!actor->GetDirtyFlag())
  60. {
  61. return DirtyFileManager::NOFILESTOSAVE;
  62. }
  63. // and files that really represent an actor that we take serious in emstudio :)
  64. if (actor->GetIsUsedForVisualization())
  65. {
  66. return DirtyFileManager::NOFILESTOSAVE;
  67. }
  68. if (askBeforeSaving)
  69. {
  70. EMStudio::GetApp()->setOverrideCursor(QCursor(Qt::ArrowCursor));
  71. QMessageBox msgBox(GetMainWindow());
  72. AZStd::string text;
  73. AZStd::string filename = actor->GetFileNameString();
  74. AZStd::string extension;
  75. AzFramework::StringFunc::Path::GetExtension(filename.c_str(), extension, false /* include dot */);
  76. if (!filename.empty() &&
  77. !extension.empty())
  78. {
  79. text = AZStd::string::format("Save changes to '%s'?", actor->GetFileName());
  80. }
  81. else if (!actor->GetNameString().empty())
  82. {
  83. text = AZStd::string::format("Save changes to the actor named '%s'?", actor->GetName());
  84. }
  85. else
  86. {
  87. text = "Save changes to untitled actor?";
  88. }
  89. msgBox.setText(text.c_str());
  90. msgBox.setWindowTitle("Save Changes");
  91. if (showCancelButton)
  92. {
  93. msgBox.setStandardButtons(QMessageBox::Save | QMessageBox::Discard | QMessageBox::Cancel);
  94. }
  95. else
  96. {
  97. msgBox.setStandardButtons(QMessageBox::Save | QMessageBox::Discard);
  98. }
  99. msgBox.setDefaultButton(QMessageBox::Save);
  100. msgBox.setIcon(QMessageBox::Question);
  101. int messageBoxResult = msgBox.exec();
  102. switch (messageBoxResult)
  103. {
  104. case QMessageBox::Save:
  105. {
  106. GetMainWindow()->GetFileManager()->SaveActor(actor);
  107. break;
  108. }
  109. case QMessageBox::Discard:
  110. {
  111. EMStudio::GetApp()->restoreOverrideCursor();
  112. return DirtyFileManager::FINISHED;
  113. }
  114. case QMessageBox::Cancel:
  115. {
  116. EMStudio::GetApp()->restoreOverrideCursor();
  117. return DirtyFileManager::CANCELED;
  118. }
  119. }
  120. }
  121. else
  122. {
  123. // save without asking first
  124. GetMainWindow()->GetFileManager()->SaveActor(actor);
  125. }
  126. return DirtyFileManager::FINISHED;
  127. }
  128. ///////////////////////////////////////////////////////////////////////////
  129. void SaveDirtyMotionFilesCallback::GetDirtyFileNames(
  130. AZStd::vector<AZStd::string>* outFileNames, AZStd::vector<ObjectPointer>* outObjects)
  131. {
  132. const size_t numMotions = EMotionFX::GetMotionManager().GetNumMotions();
  133. for (size_t i = 0; i < numMotions; ++i)
  134. {
  135. EMotionFX::Motion* motion = EMotionFX::GetMotionManager().GetMotion(i);
  136. if (motion->GetIsOwnedByRuntime())
  137. {
  138. continue;
  139. }
  140. if (motion->GetDirtyFlag())
  141. {
  142. outFileNames->push_back(motion->GetFileName());
  143. ObjectPointer objPointer;
  144. objPointer.m_motion = motion;
  145. outObjects->push_back(objPointer);
  146. }
  147. }
  148. }
  149. int SaveDirtyMotionFilesCallback::SaveDirtyFiles(
  150. [[maybe_unused]] const AZStd::vector<AZStd::string>& filenamesToSave,
  151. const AZStd::vector<ObjectPointer>& objects,
  152. MCore::CommandGroup* commandGroup)
  153. {
  154. for (const ObjectPointer& objPointer : objects)
  155. {
  156. if (!objPointer.m_motion)
  157. {
  158. continue;
  159. }
  160. EMotionFX::Motion* motion = objPointer.m_motion;
  161. if (SaveDirtyMotion(motion, commandGroup, false) == DirtyFileManager::CANCELED)
  162. {
  163. return DirtyFileManager::CANCELED;
  164. }
  165. }
  166. return DirtyFileManager::FINISHED;
  167. }
  168. int SaveDirtyMotionFilesCallback::SaveDirtyMotion(
  169. EMotionFX::Motion* motion, [[maybe_unused]] MCore::CommandGroup* commandGroup, bool askBeforeSaving, bool showCancelButton)
  170. {
  171. // only process changed files
  172. if (!motion->GetDirtyFlag())
  173. {
  174. return DirtyFileManager::NOFILESTOSAVE;
  175. }
  176. if (askBeforeSaving)
  177. {
  178. EMStudio::GetApp()->setOverrideCursor(QCursor(Qt::ArrowCursor));
  179. QMessageBox msgBox(GetMainWindow());
  180. AZStd::string text;
  181. if (!motion->GetFileNameString().empty())
  182. {
  183. text = AZStd::string::format("Save changes to '%s'?", motion->GetFileName());
  184. }
  185. else if (!motion->GetNameString().empty())
  186. {
  187. text = AZStd::string::format("Save changes to the motion named '%s'?", motion->GetName());
  188. }
  189. else
  190. {
  191. text = "Save changes to untitled motion?";
  192. }
  193. msgBox.setText(text.c_str());
  194. msgBox.setWindowTitle("Save Changes");
  195. if (showCancelButton)
  196. {
  197. msgBox.setStandardButtons(QMessageBox::Save | QMessageBox::Discard | QMessageBox::Cancel);
  198. }
  199. else
  200. {
  201. msgBox.setStandardButtons(QMessageBox::Save | QMessageBox::Discard);
  202. }
  203. msgBox.setDefaultButton(QMessageBox::Save);
  204. msgBox.setIcon(QMessageBox::Question);
  205. int messageBoxResult = msgBox.exec();
  206. switch (messageBoxResult)
  207. {
  208. case QMessageBox::Save:
  209. {
  210. GetMainWindow()->GetFileManager()->SaveMotion(motion->GetID());
  211. break;
  212. }
  213. case QMessageBox::Discard:
  214. {
  215. EMStudio::GetApp()->restoreOverrideCursor();
  216. return DirtyFileManager::FINISHED;
  217. }
  218. case QMessageBox::Cancel:
  219. {
  220. EMStudio::GetApp()->restoreOverrideCursor();
  221. return DirtyFileManager::CANCELED;
  222. }
  223. }
  224. }
  225. else
  226. {
  227. // save without asking first
  228. GetMainWindow()->GetFileManager()->SaveMotion(motion->GetID());
  229. }
  230. return DirtyFileManager::FINISHED;
  231. }
  232. ///////////////////////////////////////////////////////////////////////////
  233. void SaveDirtyMotionSetFilesCallback::GetDirtyFileNames(
  234. AZStd::vector<AZStd::string>* outFileNames, AZStd::vector<ObjectPointer>* outObjects)
  235. {
  236. const size_t numMotionSets = EMotionFX::GetMotionManager().GetNumMotionSets();
  237. for (size_t i = 0; i < numMotionSets; ++i)
  238. {
  239. EMotionFX::MotionSet* motionSet = EMotionFX::GetMotionManager().GetMotionSet(i);
  240. if (motionSet->GetIsOwnedByRuntime())
  241. {
  242. continue;
  243. }
  244. // only save root motion sets
  245. if (motionSet->GetParentSet())
  246. {
  247. continue;
  248. }
  249. if (motionSet->GetDirtyFlag())
  250. {
  251. outFileNames->push_back(motionSet->GetFilename());
  252. ObjectPointer objPointer;
  253. objPointer.m_motionSet = motionSet;
  254. outObjects->push_back(objPointer);
  255. }
  256. }
  257. }
  258. int SaveDirtyMotionSetFilesCallback::SaveDirtyFiles(
  259. [[maybe_unused]] const AZStd::vector<AZStd::string>& filenamesToSave,
  260. const AZStd::vector<ObjectPointer>& objects,
  261. MCore::CommandGroup* commandGroup)
  262. {
  263. for (const ObjectPointer& objPointer : objects)
  264. {
  265. if (!objPointer.m_motionSet)
  266. {
  267. continue;
  268. }
  269. EMotionFX::MotionSet* motionSet = objPointer.m_motionSet;
  270. if (SaveDirtyMotionSet(motionSet, commandGroup, false) == DirtyFileManager::CANCELED)
  271. {
  272. return DirtyFileManager::CANCELED;
  273. }
  274. }
  275. return DirtyFileManager::FINISHED;
  276. }
  277. int SaveDirtyMotionSetFilesCallback::SaveDirtyMotionSet(
  278. EMotionFX::MotionSet* motionSet, MCore::CommandGroup* commandGroup, bool askBeforeSaving, bool showCancelButton)
  279. {
  280. // only save root motion sets
  281. if (motionSet->GetParentSet())
  282. {
  283. return DirtyFileManager::NOFILESTOSAVE;
  284. }
  285. // only process changed files
  286. if (!motionSet->GetDirtyFlag())
  287. {
  288. return DirtyFileManager::NOFILESTOSAVE;
  289. }
  290. if (askBeforeSaving)
  291. {
  292. EMStudio::GetApp()->setOverrideCursor(QCursor(Qt::ArrowCursor));
  293. QMessageBox msgBox(GetMainWindow());
  294. AZStd::string text;
  295. const AZStd::string& filename = motionSet->GetFilenameString();
  296. AZStd::string extension;
  297. AzFramework::StringFunc::Path::GetExtension(filename.c_str(), extension, false /* include dot */);
  298. if (!filename.empty() && !extension.empty())
  299. {
  300. text = AZStd::string::format("Save changes to '%s'?", motionSet->GetFilename());
  301. }
  302. else if (!motionSet->GetNameString().empty())
  303. {
  304. text = AZStd::string::format("Save changes to the motion set named '%s'?", motionSet->GetName());
  305. }
  306. else
  307. {
  308. text = "Save changes to untitled motion set?";
  309. }
  310. msgBox.setText(text.c_str());
  311. msgBox.setWindowTitle("Save Changes");
  312. if (showCancelButton)
  313. {
  314. msgBox.setStandardButtons(QMessageBox::Save | QMessageBox::Discard | QMessageBox::Cancel);
  315. }
  316. else
  317. {
  318. msgBox.setStandardButtons(QMessageBox::Save | QMessageBox::Discard);
  319. }
  320. msgBox.setDefaultButton(QMessageBox::Save);
  321. msgBox.setIcon(QMessageBox::Question);
  322. int messageBoxResult = msgBox.exec();
  323. switch (messageBoxResult)
  324. {
  325. case QMessageBox::Save:
  326. {
  327. GetMainWindow()->GetFileManager()->SaveMotionSet(GetMainWindow(), motionSet, commandGroup);
  328. break;
  329. }
  330. case QMessageBox::Discard:
  331. {
  332. EMStudio::GetApp()->restoreOverrideCursor();
  333. return DirtyFileManager::FINISHED;
  334. }
  335. case QMessageBox::Cancel:
  336. {
  337. EMStudio::GetApp()->restoreOverrideCursor();
  338. return DirtyFileManager::CANCELED;
  339. }
  340. }
  341. }
  342. else
  343. {
  344. // save without asking first
  345. GetMainWindow()->GetFileManager()->SaveMotionSet(GetMainWindow(), motionSet, commandGroup);
  346. }
  347. return DirtyFileManager::FINISHED;
  348. }
  349. ///////////////////////////////////////////////////////////////////////////
  350. void SaveDirtyAnimGraphFilesCallback::GetDirtyFileNames(
  351. AZStd::vector<AZStd::string>* outFileNames, AZStd::vector<ObjectPointer>* outObjects)
  352. {
  353. const size_t numAnimGraphs = EMotionFX::GetAnimGraphManager().GetNumAnimGraphs();
  354. for (size_t i = 0; i < numAnimGraphs; ++i)
  355. {
  356. EMotionFX::AnimGraph* animGraph = EMotionFX::GetAnimGraphManager().GetAnimGraph(i);
  357. if (animGraph->GetIsOwnedByRuntime())
  358. {
  359. continue;
  360. }
  361. if (animGraph->GetDirtyFlag())
  362. {
  363. outFileNames->push_back(animGraph->GetFileName());
  364. ObjectPointer objPointer;
  365. objPointer.m_animGraph = animGraph;
  366. outObjects->push_back(objPointer);
  367. }
  368. }
  369. }
  370. int SaveDirtyAnimGraphFilesCallback::SaveDirtyFiles(
  371. [[maybe_unused]] const AZStd::vector<AZStd::string>& filenamesToSave,
  372. const AZStd::vector<ObjectPointer>& objects,
  373. MCore::CommandGroup* commandGroup)
  374. {
  375. for (const ObjectPointer& objPointer : objects)
  376. {
  377. if (!objPointer.m_animGraph)
  378. {
  379. continue;
  380. }
  381. EMotionFX::AnimGraph* animGraph = objPointer.m_animGraph;
  382. if (SaveDirtyAnimGraph(animGraph, commandGroup, false) == DirtyFileManager::CANCELED)
  383. {
  384. return DirtyFileManager::CANCELED;
  385. }
  386. }
  387. return DirtyFileManager::FINISHED;
  388. }
  389. int SaveDirtyAnimGraphFilesCallback::SaveDirtyAnimGraph(
  390. EMotionFX::AnimGraph* animGraph, MCore::CommandGroup* commandGroup, bool askBeforeSaving, bool showCancelButton)
  391. {
  392. if (!animGraph)
  393. {
  394. return QMessageBox::Discard;
  395. }
  396. // only process changed files
  397. if (!animGraph->GetDirtyFlag())
  398. {
  399. return DirtyFileManager::NOFILESTOSAVE;
  400. }
  401. if (askBeforeSaving)
  402. {
  403. EMStudio::GetApp()->setOverrideCursor(QCursor(Qt::ArrowCursor));
  404. QMessageBox msgBox(GetMainWindow());
  405. AZStd::string text;
  406. if (!animGraph->GetFileNameString().empty())
  407. {
  408. text = AZStd::string::format("Save changes to '%s'?", animGraph->GetFileName());
  409. }
  410. else
  411. {
  412. text = "Save changes to untitled anim graph?";
  413. }
  414. msgBox.setText(text.c_str());
  415. msgBox.setWindowTitle("Save Changes");
  416. if (showCancelButton)
  417. {
  418. msgBox.setStandardButtons(QMessageBox::Save | QMessageBox::Discard | QMessageBox::Cancel);
  419. }
  420. else
  421. {
  422. msgBox.setStandardButtons(QMessageBox::Save | QMessageBox::Discard);
  423. }
  424. msgBox.setDefaultButton(QMessageBox::Save);
  425. msgBox.setIcon(QMessageBox::Question);
  426. int messageBoxResult = msgBox.exec();
  427. switch (messageBoxResult)
  428. {
  429. case QMessageBox::Save:
  430. {
  431. GetMainWindow()->GetFileManager()->SaveAnimGraph(GetMainWindow(), animGraph, commandGroup);
  432. break;
  433. }
  434. case QMessageBox::Discard:
  435. {
  436. EMStudio::GetApp()->restoreOverrideCursor();
  437. return DirtyFileManager::FINISHED;
  438. }
  439. case QMessageBox::Cancel:
  440. {
  441. EMStudio::GetApp()->restoreOverrideCursor();
  442. return DirtyFileManager::CANCELED;
  443. }
  444. }
  445. }
  446. else
  447. {
  448. // save without asking first
  449. GetMainWindow()->GetFileManager()->SaveAnimGraph(GetMainWindow(), animGraph, commandGroup);
  450. }
  451. return DirtyFileManager::FINISHED;
  452. }
  453. ///////////////////////////////////////////////////////////////////////////
  454. void SaveDirtyWorkspaceCallback::GetDirtyFileNames(AZStd::vector<AZStd::string>* outFileNames, AZStd::vector<ObjectPointer>* outObjects)
  455. {
  456. Workspace* workspace = GetManager()->GetWorkspace();
  457. if (workspace->GetDirtyFlag())
  458. {
  459. // add the filename to the dirty filenames array
  460. outFileNames->push_back(workspace->GetFilename());
  461. // add the link to the actual object
  462. ObjectPointer objPointer;
  463. objPointer.m_workspace = workspace;
  464. outObjects->push_back(objPointer);
  465. }
  466. }
  467. int SaveDirtyWorkspaceCallback::SaveDirtyFiles(
  468. [[maybe_unused]] const AZStd::vector<AZStd::string>& filenamesToSave,
  469. const AZStd::vector<ObjectPointer>& objects,
  470. MCore::CommandGroup* commandGroup)
  471. {
  472. for (const ObjectPointer& objPointer : objects)
  473. {
  474. if (!objPointer.m_workspace)
  475. {
  476. continue;
  477. }
  478. Workspace* workspace = objPointer.m_workspace;
  479. // has the workspace been saved already or is it a new one?
  480. if (workspace->GetFilenameString().empty())
  481. {
  482. // open up save as dialog so that we can choose a filename
  483. const AZStd::string filename = GetMainWindow()->GetFileManager()->SaveWorkspaceFileDialog(GetMainWindow());
  484. if (filename.empty())
  485. {
  486. return DirtyFileManager::CANCELED;
  487. }
  488. // save the workspace using the newly selected filename
  489. AZStd::string command = AZStd::string::format("SaveWorkspace -filename \"%s\"", filename.c_str());
  490. commandGroup->AddCommandString(command);
  491. }
  492. else
  493. {
  494. // save workspace using its filename
  495. AZStd::string command = AZStd::string::format("SaveWorkspace -filename \"%s\"", workspace->GetFilename());
  496. commandGroup->AddCommandString(command);
  497. }
  498. }
  499. return DirtyFileManager::FINISHED;
  500. }
  501. } // namespace EMStudio