3
0

Util.cpp 47 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084108510861087108810891090109110921093109410951096
  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 <Atom/ImageProcessing/ImageObject.h>
  9. #include <Atom/ImageProcessing/ImageProcessingBus.h>
  10. #include <Atom/RPI.Edit/Common/AssetUtils.h>
  11. #include <Atom/RPI.Reflect/Asset/AssetUtils.h>
  12. #include <AtomToolsFramework/Util/Util.h>
  13. #include <AzCore/IO/ByteContainerStream.h>
  14. #include <AzCore/IO/SystemFile.h>
  15. #include <AzCore/Jobs/Algorithms.h>
  16. #include <AzCore/Jobs/JobFunction.h>
  17. #include <AzCore/Settings/SettingsRegistry.h>
  18. #include <AzCore/Settings/SettingsRegistryMergeUtils.h>
  19. #include <AzCore/StringFunc/StringFunc.h>
  20. #include <AzCore/Utils/Utils.h>
  21. #include <AzCore/std/algorithm.h>
  22. #include <AzCore/std/sort.h>
  23. #include <AzCore/std/string/regex.h>
  24. #include <AzFramework/API/ApplicationAPI.h>
  25. #include <AzFramework/FileFunc/FileFunc.h>
  26. #include <AzQtComponents/Components/Widgets/FileDialog.h>
  27. #include <AzToolsFramework/API/EditorAssetSystemAPI.h>
  28. #include <AzToolsFramework/API/EditorPythonRunnerRequestsBus.h>
  29. #include <AzToolsFramework/API/EditorWindowRequestBus.h>
  30. #include <AzToolsFramework/AssetBrowser/AssetBrowserBus.h>
  31. #include <AzToolsFramework/AssetBrowser/AssetBrowserEntry.h>
  32. #include <AzToolsFramework/AssetBrowser/AssetSelectionModel.h>
  33. #include <AzToolsFramework/AssetBrowser/Entries/AssetBrowserEntryUtils.h>
  34. #include <AzToolsFramework/AssetDatabase/AssetDatabaseConnection.h>
  35. #include <AzToolsFramework/ToolsComponents/EditorAssetMimeDataContainer.h>
  36. AZ_PUSH_DISABLE_WARNING(4251 4800, "-Wunknown-warning-option") // disable warnings spawned by QT
  37. #include <QApplication>
  38. #include <QDialog>
  39. #include <QDialogButtonBox>
  40. #include <QListWidget>
  41. #include <QMenu>
  42. #include <QMessageBox>
  43. #include <QMimeData>
  44. #include <QProcess>
  45. #include <QTimer>
  46. #include <QVBoxLayout>
  47. AZ_POP_DISABLE_WARNING
  48. namespace AtomToolsFramework
  49. {
  50. void LoadImageAsync(const AZStd::string& path, LoadImageAsyncCallback callback)
  51. {
  52. AZ::Job* job = AZ::CreateJobFunction(
  53. [path, callback]()
  54. {
  55. ImageProcessingAtom::IImageObjectPtr imageObject;
  56. ImageProcessingAtom::ImageProcessingRequestBus::BroadcastResult(
  57. imageObject, &ImageProcessingAtom::ImageProcessingRequests::LoadImagePreview, path);
  58. if (imageObject)
  59. {
  60. AZ::u8* imageBuf = nullptr;
  61. AZ::u32 pitch = 0;
  62. AZ::u32 mip = 0;
  63. imageObject->GetImagePointer(mip, imageBuf, pitch);
  64. const AZ::u32 width = imageObject->GetWidth(mip);
  65. const AZ::u32 height = imageObject->GetHeight(mip);
  66. QImage image(imageBuf, width, height, pitch, QImage::Format_RGBA8888);
  67. if (callback)
  68. {
  69. callback(image);
  70. }
  71. }
  72. },
  73. true);
  74. job->Start();
  75. }
  76. QWidget* GetToolMainWindow()
  77. {
  78. QWidget* mainWindow = QApplication::activeWindow();
  79. AzToolsFramework::EditorWindowRequestBus::BroadcastResult(
  80. mainWindow, &AzToolsFramework::EditorWindowRequestBus::Events::GetAppMainWindow);
  81. return mainWindow;
  82. }
  83. AZStd::string GetFirstNonEmptyString(const AZStd::vector<AZStd::string>& values, const AZStd::string& defaultValue)
  84. {
  85. for (const auto& value : values)
  86. {
  87. if (!value.empty())
  88. {
  89. return value;
  90. }
  91. }
  92. return defaultValue;
  93. }
  94. void ReplaceSymbolsInContainer(const AZStd::string& findText, const AZStd::string& replaceText, AZStd::vector<AZStd::string>& container)
  95. {
  96. const AZStd::regex findRegex(findText);
  97. for (auto& sourceText : container)
  98. {
  99. sourceText = AZStd::regex_replace(sourceText, findRegex, replaceText);
  100. }
  101. }
  102. void ReplaceSymbolsInContainer(
  103. const AZStd::vector<AZStd::pair<AZStd::string, AZStd::string>>& substitutionSymbols, AZStd::vector<AZStd::string>& container)
  104. {
  105. for (const auto& substitutionSymbolPair : substitutionSymbols)
  106. {
  107. ReplaceSymbolsInContainer(substitutionSymbolPair.first, substitutionSymbolPair.second, container);
  108. }
  109. }
  110. AZStd::string GetSymbolNameFromText(const AZStd::string& text)
  111. {
  112. QString symbolName(text.c_str());
  113. // Remove all leading whitespace
  114. symbolName.replace(QRegExp("^\\s+"), "");
  115. // Remove all trailing whitespace
  116. symbolName.replace(QRegExp("\\s+$"), "");
  117. // Replace non alphanumeric characters with _
  118. symbolName.replace(QRegExp("[^a-zA-Z\\d]"), "_");
  119. // Insert a _ between a lowercase or numeric character followed by an uppercase character
  120. symbolName.replace(QRegExp("([a-z\\d])([A-Z])"), "\\1_\\2");
  121. // Insert an underscore at the beginning of the string if it starts with a digit
  122. symbolName.replace(QRegExp("^(\\d)"), "_\\1");
  123. // Replace every sequence of whitespace characters with underscores
  124. symbolName.replace(QRegExp("\\s+"), "_");
  125. // Replace Sequences of _ with a single _
  126. symbolName.replace(QRegExp("_+"), "_");
  127. return symbolName.toLower().toUtf8().constData();
  128. }
  129. AZStd::string GetDisplayNameFromText(const AZStd::string& text)
  130. {
  131. QString displayName(text.c_str());
  132. // Remove all leading whitespace
  133. displayName.replace(QRegExp("^\\s+"), "");
  134. // Remove all trailing whitespace
  135. displayName.replace(QRegExp("\\s+$"), "");
  136. // Replace non alphanumeric characters with space
  137. displayName.replace(QRegExp("[^a-zA-Z\\d]"), " ");
  138. // Insert a space between a lowercase or numeric character followed by an uppercase character
  139. displayName.replace(QRegExp("([a-z\\d])([A-Z])"), "\\1 \\2");
  140. // Tokenize the string where separated by whitespace
  141. QStringList displayNameParts = displayName.split(QRegExp("\\s"), Qt::SkipEmptyParts);
  142. for (QString& part : displayNameParts)
  143. {
  144. // Capitalize the first character of every token
  145. part.replace(0, 1, part[0].toUpper());
  146. }
  147. // Recombine all of the strings separated by a single space
  148. return displayNameParts.join(" ").toUtf8().constData();
  149. }
  150. AZStd::string GetDisplayNameFromPath(const AZStd::string& path)
  151. {
  152. QFileInfo fileInfo(path.c_str());
  153. return GetDisplayNameFromText(fileInfo.baseName().toUtf8().constData());
  154. }
  155. bool GetStringListFromDialog(
  156. AZStd::vector<AZStd::string>& selectedStrings,
  157. const AZStd::vector<AZStd::string>& availableStrings,
  158. const AZStd::string& title,
  159. const bool multiSelect)
  160. {
  161. // Create a dialog that will display a list of string options and prompt the user for input.
  162. QDialog dialog(GetToolMainWindow());
  163. dialog.setModal(true);
  164. dialog.setWindowTitle(title.c_str());
  165. dialog.setLayout(new QVBoxLayout());
  166. // Fill the list widget with all of the available strings for the user to select.
  167. QListWidget listWidget(&dialog);
  168. listWidget.setSelectionMode(multiSelect ? QAbstractItemView::ExtendedSelection : QAbstractItemView::SingleSelection);
  169. for (const auto& availableString : availableStrings)
  170. {
  171. listWidget.addItem(availableString.c_str());
  172. }
  173. listWidget.sortItems();
  174. // The selected strings vector already has items then attempt to select those in the list.
  175. for (const auto& selection : selectedStrings)
  176. {
  177. for (auto item : listWidget.findItems(selection.c_str(), Qt::MatchExactly))
  178. {
  179. item->setSelected(true);
  180. }
  181. }
  182. // Create the button box that will provide default dialog buttons to allow the user to accept or reject their selections.
  183. QDialogButtonBox buttonBox(&dialog);
  184. buttonBox.setStandardButtons(QDialogButtonBox::Cancel | QDialogButtonBox::Ok);
  185. QObject::connect(&buttonBox, &QDialogButtonBox::accepted, &dialog, &QDialog::accept);
  186. QObject::connect(&buttonBox, &QDialogButtonBox::rejected, &dialog, &QDialog::reject);
  187. // Add the list widget and button box to the layout so they appear and the dialog.
  188. dialog.layout()->addWidget(&listWidget);
  189. dialog.layout()->addWidget(&buttonBox);
  190. // Temporarily forcing a fixed size before showing it to compensate for window management centering and resizing the dialog.
  191. dialog.setFixedSize(400, 200);
  192. dialog.show();
  193. dialog.setMinimumSize(0, 0);
  194. dialog.setMaximumSize(QWIDGETSIZE_MAX, QWIDGETSIZE_MAX);
  195. // If the user accepts their selections then the selected strings director will be cleared and refilled with them.
  196. if (dialog.exec() == QDialog::Accepted)
  197. {
  198. selectedStrings.clear();
  199. for (auto item : listWidget.selectedItems())
  200. {
  201. selectedStrings.push_back(item->text().toUtf8().constData());
  202. }
  203. return true;
  204. }
  205. return false;
  206. }
  207. AZStd::string GetFileFilterFromSupportedExtensions(const AZStd::vector<AZStd::pair<AZStd::string, AZStd::string>>& supportedExtensions)
  208. {
  209. // Build an ordered table of all of the supported extensions and their display names. This will be transformed into the file filter
  210. // that is displayed in the dialog.
  211. AZStd::map<AZStd::string, AZStd::set<AZStd::string>> orderedExtensions;
  212. for (const auto& extensionPair : supportedExtensions)
  213. {
  214. if (!extensionPair.second.empty())
  215. {
  216. // Sift all of the extensions into display name groups. If no display name was provided then we will use a default one.
  217. const auto& group = !extensionPair.first.empty() ? extensionPair.first : "Supported";
  218. // Convert the extension into a wild card.
  219. orderedExtensions[group].insert("*." + extensionPair.second);
  220. }
  221. }
  222. // Transform each of the ordered extension groups into individual file dialog filters that represent one or more extensions.
  223. AZStd::vector<AZStd::string> individualFilters;
  224. for (const auto& orderedExtensionPair : orderedExtensions)
  225. {
  226. AZStd::string combinedExtensions;
  227. AZ::StringFunc::Join(combinedExtensions, orderedExtensionPair.second, " ");
  228. individualFilters.push_back(orderedExtensionPair.first + " (" + combinedExtensions + ")");
  229. }
  230. // Combine all of the individual filters into a single expression that can be used directly with the file dialog.
  231. AZStd::string combinedFilters;
  232. AZ::StringFunc::Join(combinedFilters, individualFilters, ";;");
  233. return combinedFilters;
  234. }
  235. AZStd::string GetFirstValidSupportedExtension(const AZStd::vector<AZStd::pair<AZStd::string, AZStd::string>>& supportedExtensions)
  236. {
  237. for (const auto& extensionPair : supportedExtensions)
  238. {
  239. if (!extensionPair.second.empty())
  240. {
  241. return extensionPair.second;
  242. }
  243. }
  244. return AZStd::string();
  245. }
  246. AZStd::string GetFirstMatchingSupportedExtension(
  247. const AZStd::vector<AZStd::pair<AZStd::string, AZStd::string>>& supportedExtensions, const AZStd::string& path)
  248. {
  249. for (const auto& extensionPair : supportedExtensions)
  250. {
  251. if (!extensionPair.second.empty() && path.ends_with(extensionPair.second))
  252. {
  253. return extensionPair.second;
  254. }
  255. }
  256. return AZStd::string();
  257. }
  258. AZStd::string GetSaveFilePathFromDialog(
  259. const AZStd::string& initialPath,
  260. const AZStd::vector<AZStd::pair<AZStd::string, AZStd::string>>& supportedExtensions,
  261. const AZStd::string& title)
  262. {
  263. // Build the file dialog filter from all of the supported extensions.
  264. const auto& combinedFilters = GetFileFilterFromSupportedExtensions(supportedExtensions);
  265. // If no valid extensions were provided then return immediately.
  266. if (combinedFilters.empty())
  267. {
  268. QMessageBox::critical(GetToolMainWindow(), "Error", QString("No supported extensions were specified."));
  269. return AZStd::string();
  270. }
  271. // Remove any aliasing from the initial path to feed to the file dialog.
  272. AZStd::string displayedPath = GetPathWithoutAlias(initialPath);
  273. // If the display name is empty or invalid then build a unique default display name using the first supported extension.
  274. if (displayedPath.empty())
  275. {
  276. displayedPath = GetUniqueUntitledFilePath(GetFirstValidSupportedExtension(supportedExtensions));
  277. }
  278. // Prompt the user to select a save file name using the input path and the list of filtered extensions.
  279. const QFileInfo selectedFileInfo(AzQtComponents::FileDialog::GetSaveFileName(
  280. GetToolMainWindow(), QObject::tr("Save %1").arg(title.c_str()), displayedPath.c_str(), combinedFilters.c_str()));
  281. // If the returned path is empty this means that the user cancelled or escaped from the dialog and is canceling the operation.
  282. if (selectedFileInfo.absoluteFilePath().isEmpty())
  283. {
  284. return AZStd::string();
  285. }
  286. // Find the supported extension corresponding to the user selection.
  287. const auto& selectedExtension =
  288. GetFirstMatchingSupportedExtension(supportedExtensions, selectedFileInfo.absoluteFilePath().toUtf8().constData());
  289. // If the selected path does not match any of the supported extensions consider it invalid and return.
  290. if (selectedExtension.empty())
  291. {
  292. QMessageBox::critical(GetToolMainWindow(), "Error", QString("File name does not match supported extension."));
  293. return AZStd::string();
  294. }
  295. // Reconstruct the path to compensate for known problems with the file dialog and complex extensions containing multiple "." like
  296. // *.lightingpreset.azasset
  297. return QFileInfo(QString("%1/%2.%3").arg(selectedFileInfo.absolutePath()).arg(selectedFileInfo.baseName()).arg(selectedExtension.c_str()))
  298. .absoluteFilePath().toUtf8().constData();
  299. }
  300. AZStd::vector<AZStd::string> GetOpenFilePathsFromDialog(
  301. const AZStd::vector<AZStd::string>& selectedFilePaths,
  302. const AZStd::vector<AZStd::pair<AZStd::string, AZStd::string>>& supportedExtensions,
  303. const AZStd::string& title,
  304. const bool multiSelect)
  305. {
  306. // Removing aliases from all incoming paths because the asset selection model does not recognize them.
  307. AZStd::vector<AZStd::string> selectedFilePathsWithoutAliases = selectedFilePaths;
  308. for (auto& path : selectedFilePathsWithoutAliases)
  309. {
  310. path = GetPathWithoutAlias(path);
  311. }
  312. // Create a custom filter function to plug into the asset selection model. The filter function will only display source assets
  313. // matching one of the supported extensions. It will also ignore files in the cache folder, usually intermediate assets. This is
  314. // much faster than the previous iteration using regular expressions.
  315. auto filterFn = [&](const AssetBrowserEntry* entry)
  316. {
  317. if (entry->GetEntryType() != AssetBrowserEntry::AssetEntryType::Source)
  318. {
  319. return false;
  320. }
  321. const auto& path = entry->GetFullPath();
  322. return !IsPathIgnored(path) &&
  323. AZStd::any_of(
  324. supportedExtensions.begin(),
  325. supportedExtensions.end(),
  326. [&](const auto& extensionPair)
  327. {
  328. return path.ends_with(AZStd::fixed_string<32>::format(".%s", extensionPair.second.c_str()));
  329. });
  330. };
  331. AssetSelectionModel selection;
  332. selection.SetDisplayFilter(FilterConstType(new CustomFilter(filterFn)));
  333. selection.SetSelectionFilter(FilterConstType(new CustomFilter(filterFn)));
  334. selection.SetTitle(title.c_str());
  335. selection.SetMultiselect(multiSelect);
  336. selection.SetSelectedFilePaths(selectedFilePathsWithoutAliases);
  337. AzToolsFramework::AssetBrowser::AssetBrowserComponentRequestBus::Broadcast(
  338. &AzToolsFramework::AssetBrowser::AssetBrowserComponentRequests::PickAssets, selection, GetToolMainWindow());
  339. // Return absolute paths for all results.
  340. AZStd::vector<AZStd::string> results;
  341. results.reserve(selection.GetResults().size());
  342. for (const auto& result : selection.GetResults())
  343. {
  344. results.push_back(result->GetFullPath());
  345. }
  346. return results;
  347. }
  348. AZStd::string GetUniqueFilePath(const AZStd::string& initialPath)
  349. {
  350. int counter = 0;
  351. QFileInfo fileInfo(initialPath.c_str());
  352. const QString extension = "." + fileInfo.completeSuffix();
  353. const QString basePathAndName = fileInfo.absoluteFilePath().left(fileInfo.absoluteFilePath().size() - extension.size());
  354. while (fileInfo.exists())
  355. {
  356. fileInfo = QString("%1_%2%3").arg(basePathAndName).arg(++counter).arg(extension);
  357. }
  358. return fileInfo.absoluteFilePath().toUtf8().constData();
  359. }
  360. AZStd::string GetUniqueUntitledFilePath(const AZStd::string& extension)
  361. {
  362. return GetUniqueFilePath(AZStd::string::format("%s/Assets/untitled.%s", AZ::Utils::GetProjectPath().c_str(), extension.c_str()));
  363. }
  364. bool ValidateDocumentPath(AZStd::string& path)
  365. {
  366. if (path.empty())
  367. {
  368. return false;
  369. }
  370. path = GetPathWithoutAlias(path);
  371. if (!AzFramework::StringFunc::Path::Normalize(path))
  372. {
  373. return false;
  374. }
  375. if (AzFramework::StringFunc::Path::IsRelative(path.c_str()))
  376. {
  377. return false;
  378. }
  379. if (!IsDocumentPathInSupportedFolder(path))
  380. {
  381. return false;
  382. }
  383. if (!IsDocumentPathEditable(path))
  384. {
  385. return false;
  386. }
  387. return true;
  388. }
  389. bool IsDocumentPathInSupportedFolder(const AZStd::string& path)
  390. {
  391. const auto& fullPath = GetPathWithoutAlias(path);
  392. const AZ::IO::FixedMaxPath assetPath = AZ::IO::PathView(fullPath).LexicallyNormal();
  393. for (const auto& assetFolder : GetSupportedSourceFolders())
  394. {
  395. // Check if the path is relative to the asset folder
  396. if (assetPath.IsRelativeTo(AZ::IO::PathView(assetFolder)))
  397. {
  398. return true;
  399. }
  400. }
  401. return false;
  402. }
  403. bool IsDocumentPathEditable(const AZStd::string& path)
  404. {
  405. const AZStd::string pathWithoutAlias = GetPathWithoutAlias(path);
  406. for (const auto& [storedPath, flag] :
  407. GetSettingsObject<AZStd::unordered_map<AZStd::string, bool>>("/O3DE/Atom/Tools/EditablePathSettings"))
  408. {
  409. if (pathWithoutAlias == GetPathWithoutAlias(storedPath))
  410. {
  411. return flag;
  412. }
  413. }
  414. return true;
  415. }
  416. bool IsDocumentPathPreviewable(const AZStd::string& path)
  417. {
  418. const AZStd::string pathWithoutAlias = GetPathWithoutAlias(path);
  419. for (const auto& [storedPath, flag] :
  420. GetSettingsObject<AZStd::unordered_map<AZStd::string, bool>>("/O3DE/Atom/Tools/PreviewablePathSettings"))
  421. {
  422. if (pathWithoutAlias == GetPathWithoutAlias(storedPath))
  423. {
  424. return flag;
  425. }
  426. }
  427. return true;
  428. }
  429. bool LaunchTool(const QString& baseName, const QStringList& arguments)
  430. {
  431. AZ::IO::FixedMaxPath engineRoot = AZ::Utils::GetEnginePath();
  432. AZ_Assert(!engineRoot.empty(), "Cannot query Engine Path");
  433. AZ::IO::FixedMaxPath launchPath =
  434. AZ::IO::FixedMaxPath(AZ::Utils::GetExecutableDirectory()) / (baseName + AZ_TRAIT_OS_EXECUTABLE_EXTENSION).toUtf8().constData();
  435. return QProcess::startDetached(launchPath.c_str(), arguments, engineRoot.c_str());
  436. }
  437. AZStd::string GetWatchFolder(const AZStd::string& sourcePath)
  438. {
  439. bool relativePathFound = false;
  440. AZStd::string relativePath;
  441. AZStd::string relativePathFolder;
  442. // GenerateRelativeSourcePath is necessary when saving new files because it allows us to get the info for files that may not exist yet.
  443. AzToolsFramework::AssetSystemRequestBus::BroadcastResult(
  444. relativePathFound,
  445. &AzToolsFramework::AssetSystem::AssetSystemRequest::GenerateRelativeSourcePath,
  446. sourcePath,
  447. relativePath,
  448. relativePathFolder);
  449. return relativePathFolder;
  450. }
  451. AZStd::string GetPathToExteralReference(const AZStd::string& exportPath, const AZStd::string& referencePath)
  452. {
  453. // An empty reference path signifies that there is no external reference and we can return immediately.
  454. if (referencePath.empty())
  455. {
  456. return {};
  457. }
  458. // Path aliases should be supported wherever possible to allow referencing files between different gems and projects. De-alias the
  459. // paths to compare them and attempt to generate a relative path.
  460. AZ::IO::FixedMaxPath exportPathWithoutAlias;
  461. AZ::IO::FileIOBase::GetInstance()->ReplaceAlias(exportPathWithoutAlias, AZ::IO::PathView{ exportPath });
  462. const AZ::IO::PathView exportFolder = exportPathWithoutAlias.ParentPath();
  463. AZ::IO::FixedMaxPath referencePathWithoutAlias;
  464. AZ::IO::FileIOBase::GetInstance()->ReplaceAlias(referencePathWithoutAlias, AZ::IO::PathView{ referencePath });
  465. // If both paths are contained underneath the same watch folder hierarchy then attempt to construct a relative path between them.
  466. if (GetWatchFolder(exportPath) == GetWatchFolder(referencePath))
  467. {
  468. const auto relativePath = referencePathWithoutAlias.LexicallyRelative(exportFolder);
  469. if (!relativePath.empty())
  470. {
  471. return relativePath.StringAsPosix();
  472. }
  473. }
  474. // If a relative path could not be constructed from the export path to the reference path then return the aliased path for the
  475. // reference.
  476. return GetPathWithAlias(referencePath);
  477. }
  478. bool SaveSettingsToFile(const AZ::IO::FixedMaxPath& savePath, const AZStd::vector<AZStd::string>& filters)
  479. {
  480. auto registry = AZ::SettingsRegistry::Get();
  481. if (registry == nullptr)
  482. {
  483. AZ_Warning("AtomToolsFramework", false, "Unable to access global settings registry.");
  484. return false;
  485. }
  486. AZ::SettingsRegistryMergeUtils::DumperSettings dumperSettings;
  487. dumperSettings.m_prettifyOutput = true;
  488. dumperSettings.m_includeFilter = [filters](AZStd::string_view path)
  489. {
  490. for (const auto& filter : filters)
  491. {
  492. if (filter.starts_with(path.substr(0, filter.size())))
  493. {
  494. return true;
  495. }
  496. }
  497. return false;
  498. };
  499. AZStd::string stringBuffer;
  500. AZ::IO::ByteContainerStream stringStream(&stringBuffer);
  501. if (!AZ::SettingsRegistryMergeUtils::DumpSettingsRegistryToStream(*registry, "", stringStream, dumperSettings))
  502. {
  503. AZ_Warning("AtomToolsFramework", false, R"(Unable to save changes to the registry file at "%s"\n)", savePath.c_str());
  504. return false;
  505. }
  506. if (stringBuffer.empty())
  507. {
  508. return false;
  509. }
  510. bool saved = false;
  511. constexpr auto configurationMode =
  512. AZ::IO::SystemFile::SF_OPEN_CREATE | AZ::IO::SystemFile::SF_OPEN_CREATE_PATH | AZ::IO::SystemFile::SF_OPEN_WRITE_ONLY;
  513. if (AZ::IO::SystemFile outputFile; outputFile.Open(savePath.c_str(), configurationMode))
  514. {
  515. saved = outputFile.Write(stringBuffer.c_str(), stringBuffer.size()) == stringBuffer.size();
  516. }
  517. AZ_Warning("AtomToolsFramework", saved, R"(Unable to save registry file to path "%s"\n)", savePath.c_str());
  518. return saved;
  519. }
  520. AZStd::string GetPathWithoutAlias(const AZStd::string& path)
  521. {
  522. AZ::IO::FixedMaxPath pathWithoutAlias;
  523. AZ::IO::FileIOBase::GetInstance()->ReplaceAlias(pathWithoutAlias, AZ::IO::PathView{ path });
  524. return pathWithoutAlias.StringAsPosix();
  525. }
  526. AZStd::string GetPathWithAlias(const AZStd::string& path)
  527. {
  528. AZ::IO::FixedMaxPath pathWithAlias;
  529. AZ::IO::FileIOBase::GetInstance()->ConvertToAlias(pathWithAlias, AZ::IO::PathView{ path });
  530. return pathWithAlias.StringAsPosix();
  531. }
  532. AZStd::set<AZStd::string> GetPathsFromMimeData(const QMimeData* mimeData)
  533. {
  534. AZStd::set<AZStd::string> paths;
  535. if (!mimeData)
  536. {
  537. return paths;
  538. }
  539. if (mimeData->hasFormat(AzToolsFramework::EditorAssetMimeDataContainer::GetMimeType()))
  540. {
  541. AzToolsFramework::EditorAssetMimeDataContainer container;
  542. if (container.FromMimeData(mimeData))
  543. {
  544. for (const auto& asset : container.m_assets)
  545. {
  546. AZStd::string path = AZ::RPI::AssetUtils::GetSourcePathByAssetId(asset.m_assetId);
  547. if (ValidateDocumentPath(path))
  548. {
  549. paths.insert(path);
  550. }
  551. }
  552. }
  553. }
  554. AZStd::vector<const AzToolsFramework::AssetBrowser::AssetBrowserEntry*> entries;
  555. if (AzToolsFramework::AssetBrowser::Utils::FromMimeData(mimeData, entries))
  556. {
  557. for (const auto entry : entries)
  558. {
  559. AZStd::string path = entry->GetFullPath();
  560. if (ValidateDocumentPath(path))
  561. {
  562. paths.insert(path);
  563. }
  564. }
  565. }
  566. for (const auto& url : mimeData->urls())
  567. {
  568. if (url.isLocalFile())
  569. {
  570. AZStd::string path = url.toLocalFile().toUtf8().constData();
  571. if (ValidateDocumentPath(path))
  572. {
  573. paths.insert(path);
  574. }
  575. }
  576. }
  577. return paths;
  578. }
  579. AZStd::string GetAbsolutePathForSourceAsset(const AZStd::string& path)
  580. {
  581. bool found = false;
  582. AZ::Data::AssetInfo sourceInfo;
  583. AZStd::string rootFolder;
  584. AzToolsFramework::AssetSystemRequestBus::BroadcastResult(
  585. found, &AzToolsFramework::AssetSystemRequestBus::Events::GetSourceInfoBySourcePath, path.c_str(), sourceInfo, rootFolder);
  586. if (found)
  587. {
  588. const AZ::IO::Path result = AZ::IO::Path(rootFolder) / sourceInfo.m_relativePath;
  589. if (!result.empty())
  590. {
  591. return result.LexicallyNormal().String();
  592. }
  593. }
  594. return path;
  595. }
  596. AZStd::vector<AZStd::string> GetPathsForAssetSourceDependencies(const AZ::Data::AssetInfo& sourceInfo)
  597. {
  598. AzToolsFramework::AssetDatabase::AssetDatabaseConnection assetDatabaseConnection;
  599. assetDatabaseConnection.OpenDatabase();
  600. AzToolsFramework::AssetDatabase::SourceDatabaseEntry sourceEntry;
  601. assetDatabaseConnection.QuerySourceBySourceName(
  602. sourceInfo.m_relativePath.c_str(),
  603. [&sourceEntry](const AzToolsFramework::AssetDatabase::SourceDatabaseEntry& entry)
  604. {
  605. sourceEntry = entry;
  606. return false;
  607. });
  608. if (sourceEntry.m_sourceGuid.IsNull())
  609. {
  610. return {};
  611. }
  612. AZStd::vector<AZStd::string> sourcePaths;
  613. assetDatabaseConnection.QueryDependsOnSourceBySourceDependency(
  614. sourceEntry.m_sourceGuid,
  615. AzToolsFramework::AssetDatabase::SourceFileDependencyEntry::DEP_Any,
  616. [&sourcePaths, &assetDatabaseConnection](AzToolsFramework::AssetDatabase::SourceFileDependencyEntry& entry)
  617. {
  618. AZStd::string dependencyName = entry.m_dependsOnSource.GetPath();
  619. if (entry.m_dependsOnSource.IsUuid())
  620. {
  621. assetDatabaseConnection.QuerySourceBySourceGuid(
  622. entry.m_dependsOnSource.GetUuid(),
  623. [&dependencyName](AzToolsFramework::AssetDatabase::SourceDatabaseEntry& entry)
  624. {
  625. dependencyName = entry.m_sourceName;
  626. return false;
  627. });
  628. }
  629. if (!dependencyName.empty())
  630. {
  631. sourcePaths.emplace_back(GetAbsolutePathForSourceAsset(dependencyName));
  632. }
  633. return true;
  634. });
  635. assetDatabaseConnection.CloseDatabase();
  636. AZStd::sort(sourcePaths.begin(), sourcePaths.end());
  637. sourcePaths.erase(AZStd::unique(sourcePaths.begin(), sourcePaths.end()), sourcePaths.end());
  638. return sourcePaths;
  639. }
  640. AZStd::vector<AZStd::string> GetPathsForAssetSourceDependenciesById(const AZ::Data::AssetId& assetId)
  641. {
  642. bool found = false;
  643. AZ::Data::AssetInfo sourceInfo;
  644. AZStd::string watchFolder;
  645. AzToolsFramework::AssetSystemRequestBus::BroadcastResult(
  646. found, &AzToolsFramework::AssetSystemRequestBus::Events::GetSourceInfoBySourceUUID, assetId.m_guid, sourceInfo, watchFolder);
  647. return GetPathsForAssetSourceDependencies(sourceInfo);
  648. }
  649. AZStd::vector<AZStd::string> GetPathsForAssetSourceDependenciesByPath(const AZStd::string& sourcePath)
  650. {
  651. bool found = false;
  652. AZ::Data::AssetInfo sourceInfo;
  653. AZStd::string watchFolder;
  654. AzToolsFramework::AssetSystemRequestBus::BroadcastResult(
  655. found,
  656. &AzToolsFramework::AssetSystemRequestBus::Events::GetSourceInfoBySourcePath,
  657. GetPathWithoutAlias(sourcePath).c_str(),
  658. sourceInfo,
  659. watchFolder);
  660. return GetPathsForAssetSourceDependencies(sourceInfo);
  661. }
  662. AZStd::vector<AZStd::string> GetPathsForAssetSourceDependents(const AZ::Data::AssetInfo& sourceInfo)
  663. {
  664. AzToolsFramework::AssetDatabase::AssetDatabaseConnection assetDatabaseConnection;
  665. assetDatabaseConnection.OpenDatabase();
  666. AzToolsFramework::AssetDatabase::SourceDatabaseEntry sourceEntry;
  667. assetDatabaseConnection.QuerySourceBySourceName(
  668. sourceInfo.m_relativePath.c_str(),
  669. [&sourceEntry](const AzToolsFramework::AssetDatabase::SourceDatabaseEntry& entry)
  670. {
  671. sourceEntry = entry;
  672. return false;
  673. });
  674. if (sourceEntry.m_sourceGuid.IsNull())
  675. {
  676. return {};
  677. }
  678. AZStd::string scanFolderPath;
  679. assetDatabaseConnection.QueryScanFolderByScanFolderID(
  680. sourceEntry.m_scanFolderPK,
  681. [&scanFolderPath](const AzToolsFramework::AssetDatabase::ScanFolderDatabaseEntry& entry)
  682. {
  683. scanFolderPath = entry.m_scanFolder;
  684. return false;
  685. });
  686. auto absolutePath = AZ::IO::Path(scanFolderPath) / sourceEntry.m_sourceName;
  687. AZStd::vector<AZStd::string> sourcePaths;
  688. assetDatabaseConnection.QuerySourceDependencyByDependsOnSource(
  689. sourceEntry.m_sourceGuid,
  690. sourceEntry.m_sourceName.c_str(),
  691. absolutePath.FixedMaxPathStringAsPosix().c_str(),
  692. AzToolsFramework::AssetDatabase::SourceFileDependencyEntry::DEP_Any,
  693. [&sourcePaths, &assetDatabaseConnection](AzToolsFramework::AssetDatabase::SourceFileDependencyEntry& entry)
  694. {
  695. AZStd::string sourceName;
  696. assetDatabaseConnection.QuerySourceBySourceGuid(
  697. entry.m_sourceGuid,
  698. [&sourceName](AzToolsFramework::AssetDatabase::SourceDatabaseEntry& entry)
  699. {
  700. sourceName = entry.m_sourceName;
  701. return false;
  702. });
  703. if (!sourceName.empty())
  704. {
  705. sourcePaths.emplace_back(GetAbsolutePathForSourceAsset(sourceName));
  706. }
  707. return true;
  708. });
  709. assetDatabaseConnection.CloseDatabase();
  710. AZStd::sort(sourcePaths.begin(), sourcePaths.end());
  711. sourcePaths.erase(AZStd::unique(sourcePaths.begin(), sourcePaths.end()), sourcePaths.end());
  712. return sourcePaths;
  713. }
  714. AZStd::vector<AZStd::string> GetPathsForAssetSourceDependentsById(const AZ::Data::AssetId& assetId)
  715. {
  716. bool found = false;
  717. AZ::Data::AssetInfo sourceInfo;
  718. AZStd::string watchFolder;
  719. AzToolsFramework::AssetSystemRequestBus::BroadcastResult(
  720. found, &AzToolsFramework::AssetSystemRequestBus::Events::GetSourceInfoBySourceUUID, assetId.m_guid, sourceInfo, watchFolder);
  721. return GetPathsForAssetSourceDependents(sourceInfo);
  722. }
  723. AZStd::vector<AZStd::string> GetPathsForAssetSourceDependentsByPath(const AZStd::string& sourcePath)
  724. {
  725. bool found = false;
  726. AZ::Data::AssetInfo sourceInfo;
  727. AZStd::string watchFolder;
  728. AzToolsFramework::AssetSystemRequestBus::BroadcastResult(
  729. found,
  730. &AzToolsFramework::AssetSystemRequestBus::Events::GetSourceInfoBySourcePath,
  731. GetPathWithoutAlias(sourcePath).c_str(),
  732. sourceInfo,
  733. watchFolder);
  734. return GetPathsForAssetSourceDependents(sourceInfo);
  735. }
  736. void VisitFilesInFolder(
  737. const AZStd::string& folder, const AZStd::function<bool(const AZStd::string&)> visitorFn, bool recurse)
  738. {
  739. if (!visitorFn || IsPathIgnored(folder))
  740. {
  741. return;
  742. }
  743. AZStd::string fullFilter = folder + AZ_CORRECT_FILESYSTEM_SEPARATOR_STRING + "*";
  744. AZ::StringFunc::Replace(fullFilter, "\\", "/");
  745. AZStd::string fullPath;
  746. AZ::IO::SystemFile::FindFiles(
  747. fullFilter.c_str(),
  748. [&](const char* item, bool is_file)
  749. {
  750. // Skip the '.' and '..' folders
  751. if ((azstricmp(".", item) == 0) || (azstricmp("..", item) == 0))
  752. {
  753. return true;
  754. }
  755. // Continue if we can
  756. fullPath.clear();
  757. if (!AzFramework::StringFunc::Path::Join(folder.c_str(), item, fullPath))
  758. {
  759. return false;
  760. }
  761. AZ::StringFunc::Replace(fullPath, "\\", "/");
  762. if (is_file)
  763. {
  764. return visitorFn(fullPath);
  765. }
  766. VisitFilesInFolder(fullPath, visitorFn, recurse);
  767. return true;
  768. });
  769. }
  770. void VisitFilesInScanFolders(const AZStd::function<bool(const AZStd::string&)> visitorFn)
  771. {
  772. if (visitorFn)
  773. {
  774. for (const AZStd::string& scanFolder : GetSupportedSourceFolders())
  775. {
  776. VisitFilesInFolder(scanFolder, visitorFn, true);
  777. }
  778. }
  779. }
  780. AZStd::vector<AZStd::string> GetPathsInSourceFoldersMatchingFilter(const AZStd::function<bool(const AZStd::string&)> filterFn)
  781. {
  782. const auto& scanFolders = GetSupportedSourceFolders();
  783. AZStd::vector<AZStd::string> results;
  784. results.reserve(scanFolders.size());
  785. AZStd::for_each(
  786. scanFolders.begin(),
  787. scanFolders.end(),
  788. [&](const AZStd::string& scanFolder)
  789. {
  790. VisitFilesInFolder(
  791. scanFolder,
  792. [&](const AZStd::string& path)
  793. {
  794. if (!filterFn || filterFn(path))
  795. {
  796. results.emplace_back(path);
  797. }
  798. return true;
  799. },
  800. true);
  801. });
  802. // Sorting the container and removing duplicate paths to ensure uniqueness in case of nested or overlapping scan folders.
  803. // This was previously done automatically with a set but using a vector for compatibility with behavior context and Python.
  804. AZStd::sort(results.begin(), results.end());
  805. results.erase(AZStd::unique(results.begin(), results.end()), results.end());
  806. return results;
  807. }
  808. AZStd::vector<AZStd::string> GetPathsInSourceFoldersMatchingExtension(const AZStd::string& extension)
  809. {
  810. if (extension.empty())
  811. {
  812. return {};
  813. }
  814. const AZStd::string& extensionWithDot = (extension[0] == '.') ? extension : AZStd::string::format(".%s", extension.c_str());
  815. return GetPathsInSourceFoldersMatchingFilter(
  816. [&](const AZStd::string& path)
  817. {
  818. return path.ends_with(extensionWithDot) && IsDocumentPathEditable(path);
  819. });
  820. }
  821. bool IsPathIgnored(const AZStd::string& path)
  822. {
  823. // Ignoring the cache folder is currently the most common case for tools that want to ignore intermediate assets
  824. const bool ignoreCacheFolder = GetSettingsValue("/O3DE/AtomToolsFramework/Application/IgnoreCacheFolder", true);
  825. if (ignoreCacheFolder && AZ::StringFunc::Contains(path, "cache"))
  826. {
  827. return true;
  828. }
  829. // For more extensive customization, pattern matching is also supported via IgnoredPathRegexPatterns. This is empty by default.
  830. for (const auto& patternStr : GetSettingsObject("/O3DE/AtomToolsFramework/Application/IgnoredPathRegexPatterns", AZStd::vector<AZStd::string>{}))
  831. {
  832. if (!patternStr.empty())
  833. {
  834. AZStd::regex patternRegex(patternStr, AZStd::regex::flag_type::icase);
  835. if (AZStd::regex_match(path, patternRegex))
  836. {
  837. return true;
  838. }
  839. }
  840. }
  841. return false;
  842. }
  843. AZStd::vector<AZStd::string> GetSupportedSourceFolders()
  844. {
  845. AZStd::vector<AZStd::string> scanFolders;
  846. scanFolders.reserve(100);
  847. AzToolsFramework::AssetSystemRequestBus::Broadcast(
  848. &AzToolsFramework::AssetSystem::AssetSystemRequest::GetAssetSafeFolders, scanFolders);
  849. AZStd::erase_if(scanFolders, [](const AZStd::string& path){ return IsPathIgnored(path); });
  850. return scanFolders;
  851. }
  852. void AddRegisteredScriptToMenu(QMenu* menu, const AZStd::string& registryKey, const AZStd::vector<AZStd::string>& arguments)
  853. {
  854. // Map containing vectors of script file paths organized by category
  855. using ScriptsSettingsMap = AZStd::map<AZStd::string, AZStd::vector<AZStd::string>>;
  856. // Retrieve and iterate over all of the registered script settings to add them to the menu
  857. for (const auto& [scriptCategoryName, scriptPathVec] : GetSettingsObject(registryKey, ScriptsSettingsMap()))
  858. {
  859. // Create a parent category menu group to contain all of the individual script menu actions.
  860. QMenu* scriptCategoryMenu = menu;
  861. if (!scriptCategoryName.empty())
  862. {
  863. scriptCategoryMenu = menu->findChild<QMenu*>(scriptCategoryName.c_str());
  864. if (!scriptCategoryMenu)
  865. {
  866. scriptCategoryMenu = menu->addMenu(scriptCategoryName.c_str());
  867. }
  868. }
  869. // Create menu actions for executing the individual scripts.
  870. for (AZStd::string scriptPath : scriptPathVec)
  871. {
  872. // Removing the alias for the path so that we can check for its existence and add it to the menu.
  873. scriptPath = GetPathWithoutAlias(scriptPath);
  874. if (QFile::exists(scriptPath.c_str()))
  875. {
  876. // Use the file name instead of the full path as the display name for the menu action.
  877. AZStd::string filename;
  878. AZ::StringFunc::Path::GetFullFileName(scriptPath.c_str(), filename);
  879. scriptCategoryMenu->addAction(filename.c_str(), [scriptPath, arguments]() {
  880. // Delay execution of the script until the next frame.
  881. AZ::SystemTickBus::QueueFunction([scriptPath, arguments]() {
  882. AzToolsFramework::EditorPythonRunnerRequestBus::Broadcast(
  883. &AzToolsFramework::EditorPythonRunnerRequestBus::Events::ExecuteByFilenameWithArgs,
  884. scriptPath,
  885. AZStd::vector<AZStd::string_view>(arguments.begin(), arguments.end()));
  886. });
  887. });
  888. }
  889. }
  890. }
  891. // Create menu action for running arbitrary Python script.
  892. menu->addAction(QObject::tr("&Run Python Script..."), [arguments]() {
  893. const QString scriptPath = QFileDialog::getOpenFileName(
  894. GetToolMainWindow(), QObject::tr("Run Python Script"), QString(AZ::Utils::GetProjectPath().c_str()), QString("*.py"));
  895. if (!scriptPath.isEmpty())
  896. {
  897. // Delay execution of the script until the next frame.
  898. AZ::SystemTickBus::QueueFunction([scriptPath, arguments]() {
  899. AzToolsFramework::EditorPythonRunnerRequestBus::Broadcast(
  900. &AzToolsFramework::EditorPythonRunnerRequestBus::Events::ExecuteByFilenameWithArgs,
  901. scriptPath.toUtf8().constData(),
  902. AZStd::vector<AZStd::string_view>(arguments.begin(), arguments.end()));
  903. });
  904. }
  905. });
  906. }
  907. void ReflectUtilFunctions(AZ::ReflectContext* context)
  908. {
  909. if (auto behaviorContext = azrtti_cast<AZ::BehaviorContext*>(context))
  910. {
  911. // This will put these methods into the 'azlmbr.atomtools.util' module
  912. auto addUtilFunc = [](AZ::BehaviorContext::GlobalMethodBuilder methodBuilder)
  913. {
  914. methodBuilder->Attribute(AZ::Script::Attributes::Scope, AZ::Script::Attributes::ScopeFlags::Automation)
  915. ->Attribute(AZ::Script::Attributes::Category, "Editor")
  916. ->Attribute(AZ::Script::Attributes::Module, "atomtools.util");
  917. };
  918. addUtilFunc(behaviorContext->Method("GetSymbolNameFromText", GetSymbolNameFromText, nullptr, ""));
  919. addUtilFunc(behaviorContext->Method("GetDisplayNameFromText", GetDisplayNameFromText, nullptr, ""));
  920. addUtilFunc(behaviorContext->Method("GetDisplayNameFromPath", GetDisplayNameFromPath, nullptr, ""));
  921. addUtilFunc(behaviorContext->Method("GetStringListFromDialog", GetStringListFromDialog, nullptr, ""));
  922. addUtilFunc(behaviorContext->Method("GetFileFilterFromSupportedExtensions", GetFileFilterFromSupportedExtensions, nullptr, ""));
  923. addUtilFunc(behaviorContext->Method("GetFirstValidSupportedExtension", GetFirstValidSupportedExtension, nullptr, ""));
  924. addUtilFunc(behaviorContext->Method("GetFirstMatchingSupportedExtension", GetFirstMatchingSupportedExtension, nullptr, ""));
  925. addUtilFunc(behaviorContext->Method("GetSaveFilePathFromDialog", GetSaveFilePathFromDialog, nullptr, ""));
  926. addUtilFunc(behaviorContext->Method("GetOpenFilePathsFromDialog", GetOpenFilePathsFromDialog, nullptr, ""));
  927. addUtilFunc(behaviorContext->Method("GetUniqueFilePath", GetUniqueFilePath, nullptr, ""));
  928. addUtilFunc(behaviorContext->Method("GetUniqueUntitledFilePath", GetUniqueUntitledFilePath, nullptr, ""));
  929. addUtilFunc(behaviorContext->Method("ValidateDocumentPath", ValidateDocumentPath, nullptr, ""));
  930. addUtilFunc(behaviorContext->Method("IsDocumentPathInSupportedFolder", IsDocumentPathInSupportedFolder, nullptr, ""));
  931. addUtilFunc(behaviorContext->Method("IsDocumentPathEditable", IsDocumentPathEditable, nullptr, ""));
  932. addUtilFunc(behaviorContext->Method("IsDocumentPathPreviewable", IsDocumentPathPreviewable, nullptr, ""));
  933. addUtilFunc(behaviorContext->Method("GetPathToExteralReference", GetPathToExteralReference, nullptr, ""));
  934. addUtilFunc(behaviorContext->Method("GetPathWithoutAlias", GetPathWithoutAlias, nullptr, ""));
  935. addUtilFunc(behaviorContext->Method("GetPathWithAlias", GetPathWithAlias, nullptr, ""));
  936. addUtilFunc(behaviorContext->Method("GetAbsolutePathForSourceAsset", GetAbsolutePathForSourceAsset, nullptr, ""));
  937. addUtilFunc(behaviorContext->Method("GetPathsForAssetSourceDependencies", GetPathsForAssetSourceDependencies, nullptr, ""));
  938. addUtilFunc(behaviorContext->Method("GetPathsForAssetSourceDependenciesById", GetPathsForAssetSourceDependenciesById, nullptr, ""));
  939. addUtilFunc(behaviorContext->Method("GetPathsForAssetSourceDependenciesByPath", GetPathsForAssetSourceDependenciesByPath, nullptr, ""));
  940. addUtilFunc(behaviorContext->Method("GetPathsForAssetSourceDependents", GetPathsForAssetSourceDependents, nullptr, ""));
  941. addUtilFunc(behaviorContext->Method("GetPathsForAssetSourceDependentsById", GetPathsForAssetSourceDependentsById, nullptr, ""));
  942. addUtilFunc(behaviorContext->Method("GetPathsForAssetSourceDependentsByPath", GetPathsForAssetSourceDependentsByPath, nullptr, ""));
  943. addUtilFunc(behaviorContext->Method("GetPathsInSourceFoldersMatchingExtension", GetPathsInSourceFoldersMatchingExtension, nullptr, ""));
  944. addUtilFunc(behaviorContext->Method("IsPathIgnored", IsPathIgnored, nullptr, ""));
  945. addUtilFunc(behaviorContext->Method("GetSupportedSourceFolders", GetSupportedSourceFolders, nullptr, ""));
  946. addUtilFunc(behaviorContext->Method("GetSettingsValue_bool", GetSettingsValue<bool>, nullptr, ""));
  947. addUtilFunc(behaviorContext->Method("SetSettingsValue_bool", SetSettingsValue<bool>, nullptr, ""));
  948. addUtilFunc(behaviorContext->Method("GetSettingsValue_s64", GetSettingsValue<AZ::s64>, nullptr, ""));
  949. addUtilFunc(behaviorContext->Method("SetSettingsValue_s64", SetSettingsValue<AZ::s64>, nullptr, ""));
  950. addUtilFunc(behaviorContext->Method("GetSettingsValue_u64", GetSettingsValue<AZ::u64>, nullptr, ""));
  951. addUtilFunc(behaviorContext->Method("SetSettingsValue_u64", SetSettingsValue<AZ::u64>, nullptr, ""));
  952. addUtilFunc(behaviorContext->Method("GetSettingsValue_double", GetSettingsValue<double>, nullptr, ""));
  953. addUtilFunc(behaviorContext->Method("SetSettingsValue_double", SetSettingsValue<double>, nullptr, ""));
  954. addUtilFunc(behaviorContext->Method("GetSettingsValue_string", GetSettingsValue<AZStd::string>, nullptr, ""));
  955. addUtilFunc(behaviorContext->Method("SetSettingsValue_string", SetSettingsValue<AZStd::string>, nullptr, ""));
  956. }
  957. }
  958. } // namespace AtomToolsFramework