AssetContextMenu.cpp 69 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125112611271128112911301131113211331134113511361137113811391140114111421143114411451146114711481149115011511152115311541155115611571158115911601161116211631164116511661167116811691170117111721173117411751176117711781179118011811182118311841185118611871188118911901191119211931194119511961197119811991200120112021203120412051206120712081209121012111212121312141215121612171218121912201221122212231224122512261227122812291230123112321233123412351236123712381239124012411242124312441245124612471248124912501251125212531254125512561257125812591260126112621263126412651266126712681269127012711272127312741275127612771278127912801281128212831284128512861287128812891290129112921293129412951296129712981299130013011302130313041305130613071308130913101311131213131314131513161317131813191320132113221323132413251326132713281329133013311332133313341335133613371338133913401341134213431344134513461347134813491350135113521353135413551356135713581359136013611362136313641365136613671368136913701371137213731374137513761377137813791380138113821383138413851386138713881389139013911392139313941395139613971398139914001401140214031404140514061407140814091410141114121413141414151416141714181419142014211422142314241425142614271428142914301431143214331434143514361437143814391440144114421443144414451446144714481449145014511452145314541455145614571458145914601461146214631464146514661467146814691470147114721473147414751476147714781479148014811482148314841485148614871488148914901491149214931494149514961497149814991500150115021503150415051506150715081509151015111512151315141515151615171518151915201521152215231524152515261527152815291530153115321533153415351536153715381539154015411542154315441545154615471548154915501551155215531554155515561557155815591560156115621563156415651566156715681569157015711572157315741575157615771578157915801581158215831584158515861587158815891590159115921593159415951596159715981599160016011602160316041605160616071608160916101611161216131614161516161617161816191620162116221623162416251626162716281629163016311632163316341635163616371638163916401641164216431644164516461647164816491650165116521653165416551656165716581659166016611662166316641665166616671668166916701671167216731674167516761677167816791680168116821683168416851686168716881689169016911692169316941695169616971698169917001701170217031704170517061707170817091710171117121713171417151716171717181719172017211722172317241725172617271728172917301731173217331734173517361737173817391740174117421743174417451746174717481749175017511752175317541755175617571758175917601761176217631764176517661767176817691770177117721773177417751776177717781779178017811782178317841785178617871788178917901791179217931794179517961797179817991800180118021803180418051806180718081809181018111812181318141815181618171818181918201821182218231824182518261827182818291830183118321833183418351836183718381839184018411842184318441845184618471848184918501851185218531854185518561857185818591860186118621863186418651866186718681869187018711872187318741875187618771878187918801881188218831884188518861887188818891890189118921893189418951896189718981899190019011902190319041905190619071908190919101911191219131914191519161917191819191920192119221923192419251926192719281929193019311932193319341935193619371938193919401941194219431944194519461947194819491950195119521953195419551956195719581959196019611962196319641965196619671968196919701971197219731974197519761977197819791980198119821983198419851986198719881989199019911992199319941995199619971998199920002001200220032004200520062007200820092010201120122013201420152016201720182019202020212022202320242025202620272028202920302031203220332034203520362037203820392040204120422043204420452046204720482049205020512052205320542055205620572058205920602061206220632064206520662067206820692070207120722073207420752076207720782079208020812082208320842085208620872088208920902091209220932094209520962097209820992100210121022103210421052106210721082109211021112112211321142115211621172118211921202121212221232124212521262127212821292130213121322133213421352136213721382139214021412142214321442145214621472148214921502151215221532154215521562157215821592160216121622163216421652166216721682169217021712172217321742175217621772178217921802181218221832184218521862187218821892190219121922193219421952196219721982199220022012202
  1. // Copyright 2017-2021 marynate. All Rights Reserved.
  2. #include "AssetContextMenu.h"
  3. #include "ExtAssetData.h"
  4. #include "SExtAssetView.h"
  5. #include "SMetaDataView.h"
  6. #include "ExtContentBrowserCommands.h"
  7. #include "ExtContentBrowserUtils.h"
  8. #include "ExtContentBrowserMenuContexts.h"
  9. #include "ExtContentBrowserSingleton.h"
  10. #include "Templates/SubclassOf.h"
  11. #include "Styling/SlateTypes.h"
  12. #include "Framework/Commands/UIAction.h"
  13. #include "Textures/SlateIcon.h"
  14. #include "Engine/Blueprint.h"
  15. #include "Engine/UserDefinedStruct.h"
  16. #include "Engine/UserDefinedEnum.h"
  17. #include "Misc/MessageDialog.h"
  18. #include "HAL/PlatformApplicationMisc.h"
  19. #include "HAL/FileManager.h"
  20. #include "Misc/ScopedSlowTask.h"
  21. #include "UObject/MetaData.h"
  22. #include "UObject/UObjectIterator.h"
  23. #include "Widgets/SBoxPanel.h"
  24. #include "Widgets/SWindow.h"
  25. #include "Framework/Application/SlateApplication.h"
  26. #include "Widgets/Text/STextBlock.h"
  27. #include "Widgets/Input/SMultiLineEditableTextBox.h"
  28. #include "Framework/MultiBox/MultiBoxBuilder.h"
  29. #include "ToolMenus.h"
  30. #include "Widgets/Input/SButton.h"
  31. #include "EditorStyleSet.h"
  32. #include "EditorReimportHandler.h"
  33. #include "Components/ActorComponent.h"
  34. #include "GameFramework/Actor.h"
  35. #include "UnrealClient.h"
  36. #include "Materials/MaterialFunctionInstance.h"
  37. #include "Materials/Material.h"
  38. #include "SourceControlOperations.h"
  39. #include "ISourceControlModule.h"
  40. #include "SourceControlHelpers.h"
  41. #include "Settings/EditorExperimentalSettings.h"
  42. #include "Materials/MaterialInstanceConstant.h"
  43. #include "FileHelpers.h"
  44. #include "AssetRegistry/AssetRegistryModule.h"
  45. #include "IAssetTools.h"
  46. #include "AssetToolsModule.h"
  47. #include "ContentBrowserModule.h"
  48. #include "Dialogs/Dialogs.h"
  49. #include "ObjectTools.h"
  50. #include "PackageTools.h"
  51. #include "Editor.h"
  52. #include "PropertyEditorModule.h"
  53. #include "Toolkits/GlobalEditorCommonCommands.h"
  54. #include "ConsolidateWindow.h"
  55. #include "ReferencedAssetsUtils.h"
  56. #include "Internationalization/PackageLocalizationUtil.h"
  57. #include "Internationalization/TextLocalizationResource.h"
  58. #include "SourceControlWindows.h"
  59. #include "Kismet2/KismetEditorUtilities.h"
  60. #include "ComponentAssetBroker.h"
  61. #include "Widgets/Input/SNumericEntryBox.h"
  62. #include "SourceCodeNavigation.h"
  63. #include "IDocumentation.h"
  64. #include "EditorClassUtils.h"
  65. #include "Internationalization/Culture.h"
  66. #include "Internationalization/TextPackageNamespaceUtil.h"
  67. #include "Widgets/Colors/SColorPicker.h"
  68. #include "Framework/Commands/GenericCommands.h"
  69. #include "Framework/Notifications/NotificationManager.h"
  70. #include "Widgets/Notifications/SNotificationList.h"
  71. #include "Engine/LevelStreaming.h"
  72. #include "PackageHelperFunctions.h"
  73. #include "EngineUtils.h"
  74. #include "Subsystems/AssetEditorSubsystem.h"
  75. #include "Commandlets/TextAssetCommandlet.h"
  76. #include "Misc/FileHelper.h"
  77. // Collection
  78. //#include "CollectionAssetManagement.h"
  79. #define LOCTEXT_NAMESPACE "ExtContentBrowser"
  80. FAssetContextMenu::FAssetContextMenu(const TWeakPtr<SExtAssetView>& InAssetView)
  81. : AssetView(InAssetView)
  82. , bAtLeastOneNonRedirectorSelected(false)
  83. , bAtLeastOneClassSelected(false)
  84. , bCanExecuteSCCMerge(false)
  85. , bCanExecuteSCCCheckOut(false)
  86. , bCanExecuteSCCOpenForAdd(false)
  87. , bCanExecuteSCCCheckIn(false)
  88. , bCanExecuteSCCHistory(false)
  89. , bCanExecuteSCCRevert(false)
  90. , bCanExecuteSCCSync(false)
  91. {
  92. }
  93. void FAssetContextMenu::BindCommands(TSharedPtr< FUICommandList >& Commands)
  94. {
  95. Commands->MapAction(FGlobalEditorCommonCommands::Get().FindInContentBrowser, FUIAction(
  96. FExecuteAction::CreateSP(this, &FAssetContextMenu::ExecuteSyncToAssetTree),
  97. FCanExecuteAction::CreateSP(this, &FAssetContextMenu::CanExecuteSyncToAssetTree)
  98. ));
  99. }
  100. TSharedRef<SWidget> FAssetContextMenu::MakeContextMenu(const TArray<FExtAssetData>& InSelectedAssets, const FSourcesData& InSourcesData, TSharedPtr< FUICommandList > InCommandList)
  101. {
  102. SetSelectedAssets(InSelectedAssets);
  103. SourcesData = InSourcesData;
  104. #if ECB_LEGACY
  105. // Cache any vars that are used in determining if you can execute any actions.
  106. // Useful for actions whose "CanExecute" will not change or is expensive to calculate.
  107. CacheCanExecuteVars();
  108. // Get all menu extenders for this context menu from the content browser module
  109. FContentBrowserModule& ContentBrowserModule = FModuleManager::GetModuleChecked<FContentBrowserModule>( TEXT("ContentBrowser") );
  110. TArray<FContentBrowserMenuExtender_SelectedAssets> MenuExtenderDelegates = ContentBrowserModule.GetAllAssetViewContextMenuExtenders();
  111. #endif
  112. TArray<TSharedPtr<FExtender>> Extenders;
  113. #if ECB_LEGACY
  114. for (int32 i = 0; i < MenuExtenderDelegates.Num(); ++i)
  115. {
  116. if (MenuExtenderDelegates[i].IsBound())
  117. {
  118. Extenders.Add(MenuExtenderDelegates[i].Execute(SelectedAssets));
  119. }
  120. }
  121. #endif
  122. TSharedPtr<FExtender> MenuExtender = FExtender::Combine(Extenders);
  123. UExtContentBrowserAssetContextMenuContext* ContextObject = NewObject<UExtContentBrowserAssetContextMenuContext>();
  124. ContextObject->AssetContextMenu = SharedThis(this);
  125. UToolMenus* ToolMenus = UToolMenus::Get();
  126. static const FName BaseMenuName("ExtContentBrowser.AssetContextMenu");
  127. RegisterContextMenu(BaseMenuName);
  128. TArray<UObject*> SelectedObjects;
  129. // Create menu hierarchy based on class hierarchy
  130. FName MenuName = BaseMenuName;
  131. {
  132. // Objects must be loaded for this operation... for now
  133. TArray<FString> ObjectPaths;
  134. for (int32 AssetIdx = 0; AssetIdx < SelectedAssets.Num(); ++AssetIdx)
  135. {
  136. ObjectPaths.Add(SelectedAssets[AssetIdx].ObjectPath.ToString());
  137. }
  138. ContextObject->SelectedObjects.Reset();
  139. ContextObject->SetNumSelectedObjects(SelectedAssets.Num());
  140. #if ECB_LEGACY
  141. if (ContentBrowserUtils::LoadAssetsIfNeeded(ObjectPaths, SelectedObjects) && SelectedObjects.Num() > 0)
  142. {
  143. ContextObject->SelectedObjects.Append(SelectedObjects);
  144. // Find common class for selected objects
  145. UClass* CommonClass = SelectedObjects[0]->GetClass();
  146. for (int32 ObjIdx = 1; ObjIdx < SelectedObjects.Num(); ++ObjIdx)
  147. {
  148. while (!SelectedObjects[ObjIdx]->IsA(CommonClass))
  149. {
  150. CommonClass = CommonClass->GetSuperClass();
  151. }
  152. }
  153. ContextObject->CommonClass = CommonClass;
  154. MenuName = UToolMenus::JoinMenuPaths(BaseMenuName, CommonClass->GetFName());
  155. RegisterMenuHierarchy(CommonClass);
  156. // Find asset actions for common class
  157. FAssetToolsModule& AssetToolsModule = FModuleManager::LoadModuleChecked<FAssetToolsModule>("AssetTools");
  158. TSharedPtr<IAssetTypeActions> CommonAssetTypeActions = AssetToolsModule.Get().GetAssetTypeActionsForClass(ContextObject->CommonClass).Pin();
  159. if (CommonAssetTypeActions.IsValid() && CommonAssetTypeActions->HasActions(SelectedObjects))
  160. {
  161. ContextObject->CommonAssetTypeActions = CommonAssetTypeActions;
  162. }
  163. }
  164. #endif
  165. }
  166. FToolMenuContext MenuContext(InCommandList, MenuExtender, ContextObject);
  167. return ToolMenus->GenerateWidget(MenuName, MenuContext);
  168. }
  169. void FAssetContextMenu::RegisterMenuHierarchy(UClass* InClass)
  170. {
  171. static const FName BaseMenuName("ContentBrowser.AssetContextMenu");
  172. UToolMenus* ToolMenus = UToolMenus::Get();
  173. for (UClass* CurrentClass = InClass; CurrentClass; CurrentClass = CurrentClass->GetSuperClass())
  174. {
  175. FName CurrentMenuName = UToolMenus::JoinMenuPaths(BaseMenuName, CurrentClass->GetFName());
  176. if (!ToolMenus->IsMenuRegistered(CurrentMenuName))
  177. {
  178. FName ParentMenuName;
  179. UClass* ParentClass = CurrentClass->GetSuperClass();
  180. if (ParentClass == UObject::StaticClass() || ParentClass == nullptr)
  181. {
  182. ParentMenuName = BaseMenuName;
  183. }
  184. else
  185. {
  186. ParentMenuName = UToolMenus::JoinMenuPaths(BaseMenuName, ParentClass->GetFName());
  187. }
  188. ToolMenus->RegisterMenu(CurrentMenuName, ParentMenuName);
  189. if (ParentMenuName == BaseMenuName)
  190. {
  191. break;
  192. }
  193. }
  194. }
  195. }
  196. void FAssetContextMenu::RegisterContextMenu(const FName MenuName)
  197. {
  198. UToolMenus* ToolMenus = UToolMenus::Get();
  199. if (!ToolMenus->IsMenuRegistered(MenuName))
  200. {
  201. UToolMenu* Menu = ToolMenus->RegisterMenu(MenuName);
  202. FToolMenuSection& Section = Menu->FindOrAddSection("GetAssetActions");
  203. Section.AddDynamicEntry("GetActions", FNewToolMenuSectionDelegate::CreateLambda([](FToolMenuSection& InSection)
  204. {
  205. UExtContentBrowserAssetContextMenuContext* Context = InSection.FindContext<UExtContentBrowserAssetContextMenuContext>();
  206. if (Context && Context->CommonAssetTypeActions.IsValid())
  207. {
  208. Context->CommonAssetTypeActions.Pin()->GetActions(Context->GetSelectedObjects(), InSection);
  209. }
  210. }));
  211. Section.AddDynamicEntry("GetActionsLegacy", FNewToolMenuDelegateLegacy::CreateLambda([](FMenuBuilder& MenuBuilder, UToolMenu* InMenu)
  212. {
  213. UExtContentBrowserAssetContextMenuContext* Context = InMenu->FindContext<UExtContentBrowserAssetContextMenuContext>();
  214. if (Context && Context->CommonAssetTypeActions.IsValid())
  215. {
  216. Context->CommonAssetTypeActions.Pin()->GetActions(Context->GetSelectedObjects(), MenuBuilder);
  217. }
  218. }));
  219. Menu->AddDynamicSection("AddMenuOptions", FNewToolMenuDelegate::CreateLambda([](UToolMenu* InMenu)
  220. {
  221. UExtContentBrowserAssetContextMenuContext* Context = InMenu->FindContext<UExtContentBrowserAssetContextMenuContext>();
  222. if (Context && Context->AssetContextMenu.IsValid())
  223. {
  224. Context->AssetContextMenu.Pin()->AddMenuOptions(InMenu);
  225. }
  226. }));
  227. }
  228. }
  229. void FAssetContextMenu::AddMenuOptions(UToolMenu* InMenu)
  230. {
  231. UExtContentBrowserAssetContextMenuContext* Context = InMenu->FindContext<UExtContentBrowserAssetContextMenuContext>();
  232. #if ECB_LEGACY
  233. if (!Context || Context->SelectedObjects.Num() == 0)
  234. #else
  235. if (!Context || Context->GetNumSelectedObjects() == 0)
  236. #endif
  237. {
  238. return;
  239. }
  240. // Add any type-specific context menu options
  241. AddAssetTypeMenuOptions(InMenu, Context->SelectedObjects.Num() > 0);
  242. // Add imported asset context menu options
  243. //AddImportedAssetMenuOptions(InMenu);
  244. // Add quick access to common commands.
  245. AddCommonMenuOptions(InMenu);
  246. // Add quick access to view commands
  247. AddExploreMenuOptions(InMenu);
  248. // Add reference options
  249. AddReferenceMenuOptions(InMenu);
  250. // Add copy full path options
  251. AddCopyMenuOptions(InMenu);
  252. #if ECB_WIP_COLLECTION
  253. // Add collection options
  254. AddCollectionMenuOptions(InMenu);
  255. #endif
  256. #if ECB_LEGACY
  257. // Add documentation options
  258. AddDocumentationMenuOptions(InMenu);
  259. // Add source control options
  260. AddSourceControlMenuOptions(InMenu);
  261. #endif
  262. }
  263. void FAssetContextMenu::SetSelectedAssets(const TArray<FExtAssetData>& InSelectedAssets)
  264. {
  265. SelectedAssets = InSelectedAssets;
  266. }
  267. #if ECB_LEGACY
  268. void FAssetContextMenu::SetOnFindInAssetTreeRequested(const FOnFindInAssetTreeRequested& InOnFindInAssetTreeRequested)
  269. {
  270. OnFindInAssetTreeRequested = InOnFindInAssetTreeRequested;
  271. }
  272. #endif
  273. void FAssetContextMenu::SetOnRenameRequested(const FOnRenameRequested& InOnRenameRequested)
  274. {
  275. OnRenameRequested = InOnRenameRequested;
  276. }
  277. void FAssetContextMenu::SetOnRenameFolderRequested(const FOnRenameFolderRequested& InOnRenameFolderRequested)
  278. {
  279. OnRenameFolderRequested = InOnRenameFolderRequested;
  280. }
  281. void FAssetContextMenu::SetOnDuplicateRequested(const FOnDuplicateRequested& InOnDuplicateRequested)
  282. {
  283. OnDuplicateRequested = InOnDuplicateRequested;
  284. }
  285. void FAssetContextMenu::SetOnAssetViewRefreshRequested(const FOnAssetViewRefreshRequested& InOnAssetViewRefreshRequested)
  286. {
  287. OnAssetViewRefreshRequested = InOnAssetViewRefreshRequested;
  288. }
  289. bool FAssetContextMenu::AddImportedAssetMenuOptions(UToolMenu* Menu)
  290. {
  291. #if ECB_LEGACY
  292. if (AreImportedAssetActionsVisible())
  293. {
  294. TArray<FString> ResolvedFilePaths;
  295. TArray<FString> SourceFileLabels;
  296. int32 ValidSelectedAssetCount = 0;
  297. GetSelectedAssetSourceFilePaths(ResolvedFilePaths, SourceFileLabels, ValidSelectedAssetCount);
  298. FToolMenuSection& Section = Menu->AddSection("ImportedAssetActions", LOCTEXT("ImportedAssetActionsMenuHeading", "Imported Asset"));
  299. {
  300. auto CreateSubMenu = [this](UToolMenu* SubMenu, bool bReimportWithNewFile)
  301. {
  302. //Get the data, we cannot use the closure since the lambda will be call when the function scope will be gone
  303. TArray<FString> ResolvedFilePaths;
  304. TArray<FString> SourceFileLabels;
  305. int32 ValidSelectedAssetCount = 0;
  306. GetSelectedAssetSourceFilePaths(ResolvedFilePaths, SourceFileLabels, ValidSelectedAssetCount);
  307. if (SourceFileLabels.Num() > 0 )
  308. {
  309. FToolMenuSection& SubSection = SubMenu->AddSection("Section");
  310. for (int32 SourceFileIndex = 0; SourceFileIndex < SourceFileLabels.Num(); ++SourceFileIndex)
  311. {
  312. FText ReimportLabel = FText::Format(LOCTEXT("ReimportNoLabel", "SourceFile {0}"), SourceFileIndex);
  313. FText ReimportLabelTooltip;
  314. if (ValidSelectedAssetCount == 1)
  315. {
  316. ReimportLabelTooltip = FText::Format(LOCTEXT("ReimportNoLabelTooltip", "Reimport File: {0}"), FText::FromString(ResolvedFilePaths[SourceFileIndex]));
  317. }
  318. if (SourceFileLabels[SourceFileIndex].Len() > 0)
  319. {
  320. ReimportLabel = FText::Format(LOCTEXT("ReimportLabel", "{0}"), FText::FromString(SourceFileLabels[SourceFileIndex]));
  321. if (ValidSelectedAssetCount == 1)
  322. {
  323. ReimportLabelTooltip = FText::Format(LOCTEXT("ReimportLabelTooltip", "Reimport {0} File: {1}"), FText::FromString(SourceFileLabels[SourceFileIndex]), FText::FromString(ResolvedFilePaths[SourceFileIndex]));
  324. }
  325. }
  326. if (bReimportWithNewFile)
  327. {
  328. SubSection.AddMenuEntry(
  329. NAME_None,
  330. ReimportLabel,
  331. ReimportLabelTooltip,
  332. FSlateIcon(FAppStyle::GetStyleSetName(), "ContentBrowser.AssetActions.ReimportAsset"),
  333. FUIAction(
  334. FExecuteAction::CreateSP(this, &FAssetContextMenu::ExecuteReimportWithNewFile, SourceFileIndex),
  335. FCanExecuteAction()
  336. )
  337. );
  338. }
  339. else
  340. {
  341. SubSection.AddMenuEntry(
  342. NAME_None,
  343. ReimportLabel,
  344. ReimportLabelTooltip,
  345. FSlateIcon(FAppStyle::GetStyleSetName(), "ContentBrowser.AssetActions.ReimportAsset"),
  346. FUIAction(
  347. FExecuteAction::CreateSP(this, &FAssetContextMenu::ExecuteReimport, SourceFileIndex),
  348. FCanExecuteAction()
  349. )
  350. );
  351. }
  352. }
  353. }
  354. };
  355. // Show Source In Explorer
  356. Section.AddMenuEntry(
  357. "FindSourceFile",
  358. LOCTEXT("FindSourceFile", "Open Source Location"),
  359. LOCTEXT("FindSourceFileTooltip", "Opens the folder containing the source of the selected asset(s)."),
  360. FSlateIcon(FAppStyle::GetStyleSetName(), "ContentBrowser.AssetActions.OpenSourceLocation"),
  361. FUIAction(
  362. FExecuteAction::CreateSP(this, &FAssetContextMenu::ExecuteFindSourceInExplorer, ResolvedFilePaths),
  363. FCanExecuteAction::CreateSP(this, &FAssetContextMenu::CanExecuteImportedAssetActions, ResolvedFilePaths)
  364. )
  365. );
  366. // Open In External Editor
  367. Section.AddMenuEntry(
  368. "OpenInExternalEditor",
  369. LOCTEXT("OpenInExternalEditor", "Open In External Editor"),
  370. LOCTEXT("OpenInExternalEditorTooltip", "Open the selected asset(s) in the default external editor."),
  371. FSlateIcon(FAppStyle::GetStyleSetName(), "ContentBrowser.AssetActions.OpenInExternalEditor"),
  372. FUIAction(
  373. FExecuteAction::CreateSP(this, &FAssetContextMenu::ExecuteOpenInExternalEditor, ResolvedFilePaths),
  374. FCanExecuteAction::CreateSP(this, &FAssetContextMenu::CanExecuteImportedAssetActions, ResolvedFilePaths)
  375. )
  376. );
  377. }
  378. return true;
  379. }
  380. #endif
  381. return false;
  382. }
  383. bool FAssetContextMenu::AddCommonMenuOptions(UToolMenu* Menu)
  384. {
  385. //FToolMenuSection& Section = Menu->AddSection("CommonAssetActions", LOCTEXT("CommonAssetActionsMenuHeading", "Common"));
  386. FToolMenuSection& ImportSection = Menu->AddSection("ImportAssetActions", LOCTEXT("ImportAssetActionsMenuHeading", "Import"));
  387. {
  388. // Validate
  389. ImportSection.AddMenuEntry(
  390. "Validate",
  391. LOCTEXT("Validate", "Validate"),
  392. LOCTEXT("ValidateTooltip", "Validate selected uasset files"),
  393. FSlateIcon(),
  394. FUIAction(
  395. FExecuteAction::CreateSP(this, &FAssetContextMenu::ExecuteValidateAsset),
  396. FCanExecuteAction::CreateSP(this, &FAssetContextMenu::CanExecuteValidateAsset)
  397. )
  398. );
  399. // Import
  400. ImportSection.AddMenuEntry(
  401. "Import",
  402. LOCTEXT("Import", "Import"),
  403. LOCTEXT("ImportAssetToolTip", "Import .uasset files..."),
  404. FSlateIcon(),
  405. FUIAction(
  406. FExecuteAction::CreateSP(this, &FAssetContextMenu::ExecuteImportAsset),
  407. FCanExecuteAction::CreateSP(this, &FAssetContextMenu::CanExecuteImportAsset)
  408. )
  409. );
  410. // Flat Import
  411. ImportSection.AddMenuEntry(
  412. "FlatImport",
  413. LOCTEXT("FlatImport", "Flat Import"),
  414. LOCTEXT("FlatImportTooltip", "Collect dependencies and import all into one selected folder"),
  415. FSlateIcon(),
  416. FUIAction(
  417. FExecuteAction::CreateSP(this, &FAssetContextMenu::ExecuteFlatImportAsset),
  418. FCanExecuteAction::CreateSP(this, &FAssetContextMenu::CanExecuteFlatImportAsset)
  419. )
  420. );
  421. // Direct Copy
  422. ImportSection.AddMenuEntry(
  423. "DirectCopy",
  424. LOCTEXT("DirectCopy", "Direct Copy"),
  425. LOCTEXT("DirectCopyTooltip", "Copy selected files to current project's corresonpding folder without dependency files"),
  426. FSlateIcon(),
  427. FUIAction(
  428. FExecuteAction::CreateSP(this, &FAssetContextMenu::ExecuteDirectCopyAsset),
  429. FCanExecuteAction::CreateSP(this, &FAssetContextMenu::CanExecuteDirectCopyAsset)
  430. )
  431. );
  432. }
  433. FToolMenuSection& ParseSection = Menu->AddSection("ReActions", LOCTEXT("ReActionsMenuHeading", "Re"));
  434. {
  435. // ReValidate
  436. ParseSection.AddMenuEntry(
  437. "Revalidate",
  438. LOCTEXT("Revalidate", "Revalidate"),
  439. LOCTEXT("RevalidateTooltip", "Revalidate selected uasset files"),
  440. FSlateIcon(),
  441. FUIAction(
  442. FExecuteAction::CreateSP(this, &FAssetContextMenu::ExecuteRevalidateAsset),
  443. FCanExecuteAction::CreateSP(this, &FAssetContextMenu::CanExecuteRevalidateAsset)
  444. )
  445. );
  446. #if ECB_WIP_REPARSE_ASSET
  447. // Reparse Asset
  448. ParseSection.AddMenuEntry(
  449. "ReparseAsset",
  450. LOCTEXT("ReparseAsset", "Reparse Asset"),
  451. LOCTEXT("ReparseAssetTooltip", "Reparse selected assets."),
  452. FSlateIcon(),
  453. FUIAction(
  454. FExecuteAction::CreateSP(this, &FAssetContextMenu::ExecuteReparseAsset),
  455. FCanExecuteAction::CreateSP(this, &FAssetContextMenu::CanExecuteReparseAsset)
  456. )
  457. );
  458. #endif
  459. }
  460. #if ECB_LEGACY
  461. int32 NumAssetItems, NumClassItems;
  462. ContentBrowserUtils::CountItemTypes(SelectedAssets, NumAssetItems, NumClassItems);
  463. {
  464. FToolMenuSection& Section = Menu->AddSection("CommonAssetActions", LOCTEXT("CommonAssetActionsMenuHeading", "Common"));
  465. // Edit
  466. Section.AddMenuEntry(
  467. "EditAsset",
  468. LOCTEXT("EditAsset", "Edit..."),
  469. LOCTEXT("EditAssetTooltip", "Opens the selected asset(s) for edit."),
  470. FSlateIcon(FAppStyle::GetStyleSetName(), "ContentBrowser.AssetActions.Edit"),
  471. FUIAction( FExecuteAction::CreateSP(this, &FAssetContextMenu::ExecuteEditAsset) )
  472. );
  473. // Only add these options if assets are selected
  474. if (NumAssetItems > 0)
  475. {
  476. // Rename
  477. Section.AddMenuEntry(FGenericCommands::Get().Rename,
  478. LOCTEXT("Rename", "Rename"),
  479. LOCTEXT("RenameTooltip", "Rename the selected asset."),
  480. FSlateIcon(FAppStyle::GetStyleSetName(), "ContentBrowser.AssetActions.Rename")
  481. );
  482. // Duplicate
  483. Section.AddMenuEntry(FGenericCommands::Get().Duplicate,
  484. LOCTEXT("Duplicate", "Duplicate"),
  485. LOCTEXT("DuplicateTooltip", "Create a copy of the selected asset(s)."),
  486. FSlateIcon(FAppStyle::GetStyleSetName(), "ContentBrowser.AssetActions.Duplicate")
  487. );
  488. // Save
  489. Section.AddMenuEntry(FContentBrowserCommands::Get().SaveSelectedAsset,
  490. LOCTEXT("SaveAsset", "Save"),
  491. LOCTEXT("SaveAssetTooltip", "Saves the asset to file."),
  492. FSlateIcon(FAppStyle::GetStyleSetName(), "Level.SaveIcon16x")
  493. );
  494. // Delete
  495. Section.AddMenuEntry(FGenericCommands::Get().Delete,
  496. LOCTEXT("Delete", "Delete"),
  497. LOCTEXT("DeleteTooltip", "Delete the selected assets."),
  498. FSlateIcon(FAppStyle::GetStyleSetName(), "ContentBrowser.AssetActions.Delete")
  499. );
  500. // Asset Actions sub-menu
  501. Section.AddSubMenu(
  502. "AssetActionsSubMenu",
  503. LOCTEXT("AssetActionsSubMenuLabel", "Asset Actions"),
  504. LOCTEXT("AssetActionsSubMenuToolTip", "Other asset actions"),
  505. FNewToolMenuDelegate::CreateSP(this, &FAssetContextMenu::MakeAssetActionsSubMenu),
  506. FUIAction(
  507. FExecuteAction(),
  508. FCanExecuteAction::CreateSP( this, &FAssetContextMenu::CanExecuteAssetActions )
  509. ),
  510. EUserInterfaceActionType::Button,
  511. false,
  512. FSlateIcon(FAppStyle::GetStyleSetName(), "ContentBrowser.AssetActions")
  513. );
  514. if (NumClassItems == 0)
  515. {
  516. // Asset Localization sub-menu
  517. Section.AddSubMenu(
  518. "LocalizationSubMenu",
  519. LOCTEXT("LocalizationSubMenuLabel", "Asset Localization"),
  520. LOCTEXT("LocalizationSubMenuToolTip", "Manage the localization of this asset"),
  521. FNewToolMenuDelegate::CreateSP(this, &FAssetContextMenu::MakeAssetLocalizationSubMenu),
  522. FUIAction(),
  523. EUserInterfaceActionType::Button,
  524. false,
  525. FSlateIcon(FAppStyle::GetStyleSetName(), "ContentBrowser.AssetLocalization")
  526. );
  527. }
  528. }
  529. }
  530. #endif
  531. return true;
  532. }
  533. void FAssetContextMenu::AddExploreMenuOptions(UToolMenu* Menu)
  534. {
  535. FToolMenuSection& Section = Menu->AddSection("AssetContextExploreMenuOptions", LOCTEXT("AssetContextExploreMenuOptionsHeading", "Explore"));
  536. {
  537. #if ECB_LEGACY
  538. // Find in Content Browser
  539. Section.AddMenuEntry(
  540. FGlobalEditorCommonCommands::Get().FindInContentBrowser,
  541. LOCTEXT("ShowInFolderView", "Show in Folder View"),
  542. LOCTEXT("ShowInFolderViewTooltip", "Selects the folder that contains this asset in the Content Browser Sources Panel.")
  543. );
  544. #endif
  545. // Find in Explorer
  546. Section.AddMenuEntry(
  547. "FindInExplorer",
  548. ExtContentBrowserUtils::GetExploreFolderText(),
  549. LOCTEXT("FindInExplorerTooltip", "Finds this asset on disk"),
  550. FSlateIcon(FAppStyle::Get().GetStyleSetName(), "SystemWideCommands.FindInContentBrowser"),
  551. FUIAction(
  552. FExecuteAction::CreateSP( this, &FAssetContextMenu::ExecuteFindInExplorer ),
  553. FCanExecuteAction::CreateSP( this, &FAssetContextMenu::CanExecuteFindInExplorer )
  554. )
  555. );
  556. #if ECB_FEA_SYNC_IN_CB
  557. // Sync in Content Browser
  558. Section.AddMenuEntry(
  559. "FindinContentBrowser",
  560. LOCTEXT("FindinContentBrowser", "Find in Content Browser"),
  561. LOCTEXT("FindinContentBrowserTooltip", "Find if same uasset file exists in Content Browser."),
  562. FSlateIcon(),
  563. FUIAction(
  564. FExecuteAction::CreateSP(this, &FAssetContextMenu::ExecuteSyncToContentBrowser),
  565. FCanExecuteAction::CreateSP(this, &FAssetContextMenu::CanExecuteSyncToContentBrowser)
  566. )
  567. );
  568. #endif
  569. #if ECB_WIP_IMPORT_FOR_DUMP
  570. // Dump assets via export
  571. Section.AddMenuEntry(
  572. "ExportRaw",
  573. LOCTEXT("ExportRaw", "Export Raw"),
  574. LOCTEXT("ExportRawTooltip", "Export raw aseet data from selected uasset file."),
  575. FSlateIcon(),
  576. FUIAction(
  577. FExecuteAction::CreateSP(this, &FAssetContextMenu::ExecuteDumpExport),
  578. FCanExecuteAction::CreateSP(this, &FAssetContextMenu::CanExecuteDumpExport)
  579. )
  580. );
  581. #endif
  582. }
  583. }
  584. void FAssetContextMenu::MakeAssetActionsSubMenu(UToolMenu* Menu)
  585. {
  586. #if ECB_LEGACY
  587. {
  588. FToolMenuSection& Section = Menu->AddSection("AssetActionsSection");
  589. // Create BP Using This
  590. Section.AddMenuEntry(
  591. "CreateBlueprintUsing",
  592. LOCTEXT("CreateBlueprintUsing", "Create Blueprint Using This..."),
  593. LOCTEXT("CreateBlueprintUsingTooltip", "Create a new Blueprint and add this asset to it"),
  594. FSlateIcon(FAppStyle::GetStyleSetName(), "LevelEditor.CreateClassBlueprint"),
  595. FUIAction(
  596. FExecuteAction::CreateSP(this, &FAssetContextMenu::ExecuteCreateBlueprintUsing),
  597. FCanExecuteAction::CreateSP(this, &FAssetContextMenu::CanExecuteCreateBlueprintUsing)
  598. )
  599. );
  600. // Capture Thumbnail
  601. FAssetToolsModule& AssetToolsModule = FModuleManager::LoadModuleChecked<FAssetToolsModule>("AssetTools");
  602. if (SelectedAssets.Num() == 1 && AssetToolsModule.Get().AssetUsesGenericThumbnail(SelectedAssets[0]))
  603. {
  604. Section.AddMenuEntry(
  605. "CaptureThumbnail",
  606. LOCTEXT("CaptureThumbnail", "Capture Thumbnail"),
  607. LOCTEXT("CaptureThumbnailTooltip", "Captures a thumbnail from the active viewport."),
  608. FSlateIcon(FAppStyle::GetStyleSetName(), "ContentBrowser.AssetActions.CreateThumbnail"),
  609. FUIAction(
  610. FExecuteAction::CreateSP(this, &FAssetContextMenu::ExecuteCaptureThumbnail),
  611. FCanExecuteAction::CreateSP(this, &FAssetContextMenu::CanExecuteCaptureThumbnail)
  612. )
  613. );
  614. }
  615. // Clear Thumbnail
  616. if (CanClearCustomThumbnails())
  617. {
  618. Section.AddMenuEntry(
  619. "ClearCustomThumbnail",
  620. LOCTEXT("ClearCustomThumbnail", "Clear Thumbnail"),
  621. LOCTEXT("ClearCustomThumbnailTooltip", "Clears all custom thumbnails for selected assets."),
  622. FSlateIcon(FAppStyle::GetStyleSetName(), "ContentBrowser.AssetActions.DeleteThumbnail"),
  623. FUIAction(FExecuteAction::CreateSP(this, &FAssetContextMenu::ExecuteClearThumbnail))
  624. );
  625. }
  626. }
  627. // FIND ACTIONS
  628. {
  629. FToolMenuSection& Section = Menu->AddSection("AssetContextFindActions", LOCTEXT("AssetContextFindActionsMenuHeading", "Find"));
  630. // Select Actors Using This Asset
  631. Section.AddMenuEntry(
  632. "FindAssetInWorld",
  633. LOCTEXT("FindAssetInWorld", "Select Actors Using This Asset"),
  634. LOCTEXT("FindAssetInWorldTooltip", "Selects all actors referencing this asset."),
  635. FSlateIcon(),
  636. FUIAction(
  637. FExecuteAction::CreateSP(this, &FAssetContextMenu::ExecuteFindAssetInWorld),
  638. FCanExecuteAction::CreateSP(this, &FAssetContextMenu::CanExecuteFindAssetInWorld)
  639. )
  640. );
  641. }
  642. // MOVE ACTIONS
  643. {
  644. FToolMenuSection& Section = Menu->AddSection("AssetContextMoveActions", LOCTEXT("AssetContextMoveActionsMenuHeading", "Move"));
  645. bool bHasExportableAssets = false;
  646. for (const FAssetData& AssetData : SelectedAssets)
  647. {
  648. const UObject* Object = AssetData.GetAsset();
  649. if (Object)
  650. {
  651. const UPackage* Package = Object->GetOutermost();
  652. if (!Package->HasAnyPackageFlags(EPackageFlags::PKG_DisallowExport))
  653. {
  654. bHasExportableAssets = true;
  655. break;
  656. }
  657. }
  658. }
  659. if (bHasExportableAssets)
  660. {
  661. // Export
  662. Section.AddMenuEntry(
  663. "Export",
  664. LOCTEXT("Export", "Export..."),
  665. LOCTEXT("ExportTooltip", "Export the selected assets to file."),
  666. FSlateIcon(),
  667. FUIAction( FExecuteAction::CreateSP( this, &FAssetContextMenu::ExecuteExport ) )
  668. );
  669. // Bulk Export
  670. if (SelectedAssets.Num() > 1)
  671. {
  672. Section.AddMenuEntry(
  673. "BulkExport",
  674. LOCTEXT("BulkExport", "Bulk Export..."),
  675. LOCTEXT("BulkExportTooltip", "Export the selected assets to file in the selected directory"),
  676. FSlateIcon(),
  677. FUIAction( FExecuteAction::CreateSP( this, &FAssetContextMenu::ExecuteBulkExport ) )
  678. );
  679. }
  680. }
  681. // Migrate
  682. Section.AddMenuEntry(
  683. "MigrateAsset",
  684. LOCTEXT("MigrateAsset", "Migrate..."),
  685. LOCTEXT("MigrateAssetTooltip", "Copies all selected assets and their dependencies to another project"),
  686. FSlateIcon(),
  687. FUIAction( FExecuteAction::CreateSP( this, &FAssetContextMenu::ExecuteMigrateAsset ) )
  688. );
  689. }
  690. // ADVANCED ACTIONS
  691. {
  692. FToolMenuSection& Section = Menu->AddSection("AssetContextAdvancedActions", LOCTEXT("AssetContextAdvancedActionsMenuHeading", "Advanced"));
  693. // Reload
  694. Section.AddMenuEntry(
  695. "Reload",
  696. LOCTEXT("Reload", "Reload"),
  697. LOCTEXT("ReloadTooltip", "Reload the selected assets from their file on disk."),
  698. FSlateIcon(),
  699. FUIAction(
  700. FExecuteAction::CreateSP(this, &FAssetContextMenu::ExecuteReload),
  701. FCanExecuteAction::CreateSP(this, &FAssetContextMenu::CanExecuteReload)
  702. )
  703. );
  704. // Replace References
  705. if (CanExecuteConsolidate())
  706. {
  707. Section.AddMenuEntry(
  708. "ReplaceReferences",
  709. LOCTEXT("ReplaceReferences", "Replace References"),
  710. LOCTEXT("ConsolidateTooltip", "Replace references to the selected assets."),
  711. FSlateIcon(),
  712. FUIAction(
  713. FExecuteAction::CreateSP(this, &FAssetContextMenu::ExecuteConsolidate)
  714. )
  715. );
  716. }
  717. // Property Matrix
  718. bool bCanUsePropertyMatrix = true;
  719. // Materials can't be bulk edited currently as they require very special handling because of their dependencies with the rendering thread, and we'd have to hack the property matrix too much.
  720. for (auto& Asset : SelectedAssets)
  721. {
  722. if (Asset.AssetClass == UMaterial::StaticClass()->GetFName() || Asset.AssetClass == UMaterialInstanceConstant::StaticClass()->GetFName() || Asset.AssetClass == UMaterialFunction::StaticClass()->GetFName() || Asset.AssetClass == UMaterialFunctionInstance::StaticClass()->GetFName())
  723. {
  724. bCanUsePropertyMatrix = false;
  725. break;
  726. }
  727. }
  728. if (bCanUsePropertyMatrix)
  729. {
  730. TAttribute<FText>::FGetter DynamicTooltipGetter;
  731. DynamicTooltipGetter.BindSP(this, &FAssetContextMenu::GetExecutePropertyMatrixTooltip);
  732. TAttribute<FText> DynamicTooltipAttribute = TAttribute<FText>::Create(DynamicTooltipGetter);
  733. Section.AddMenuEntry(
  734. "PropertyMatrix",
  735. LOCTEXT("PropertyMatrix", "Bulk Edit via Property Matrix..."),
  736. DynamicTooltipAttribute,
  737. FSlateIcon(),
  738. FUIAction(
  739. FExecuteAction::CreateSP(this, &FAssetContextMenu::ExecutePropertyMatrix),
  740. FCanExecuteAction::CreateSP(this, &FAssetContextMenu::CanExecutePropertyMatrix)
  741. )
  742. );
  743. }
  744. // Create Metadata menu
  745. Section.AddMenuEntry(
  746. "ShowAssetMetaData",
  747. LOCTEXT("ShowAssetMetaData", "Show Metadata"),
  748. LOCTEXT("ShowAssetMetaDataTooltip", "Show the asset metadata dialog."),
  749. FSlateIcon(),
  750. FUIAction(
  751. FExecuteAction::CreateSP(this, &FAssetContextMenu::ExecuteShowAssetMetaData),
  752. FCanExecuteAction::CreateSP(this, &FAssetContextMenu::CanExecuteShowAssetMetaData)
  753. )
  754. );
  755. // Chunk actions
  756. if (GetDefault<UEditorExperimentalSettings>()->bContextMenuChunkAssignments)
  757. {
  758. Section.AddMenuEntry(
  759. "AssignAssetChunk",
  760. LOCTEXT("AssignAssetChunk", "Assign to Chunk..."),
  761. LOCTEXT("AssignAssetChunkTooltip", "Assign this asset to a specific Chunk"),
  762. FSlateIcon(),
  763. FUIAction( FExecuteAction::CreateSP(this, &FAssetContextMenu::ExecuteAssignChunkID) )
  764. );
  765. Section.AddSubMenu(
  766. "RemoveAssetFromChunk",
  767. LOCTEXT("RemoveAssetFromChunk", "Remove from Chunk..."),
  768. LOCTEXT("RemoveAssetFromChunkTooltip", "Removed an asset from a Chunk it's assigned to."),
  769. FNewToolMenuDelegate::CreateRaw(this, &FAssetContextMenu::MakeChunkIDListMenu)
  770. );
  771. Section.AddMenuEntry(
  772. "RemoveAllChunkAssignments",
  773. LOCTEXT("RemoveAllChunkAssignments", "Remove from all Chunks"),
  774. LOCTEXT("RemoveAllChunkAssignmentsTooltip", "Removed an asset from all Chunks it's assigned to."),
  775. FSlateIcon(),
  776. FUIAction( FExecuteAction::CreateSP(this, &FAssetContextMenu::ExecuteRemoveAllChunkID) )
  777. );
  778. }
  779. }
  780. if (GetDefault<UEditorExperimentalSettings>()->bTextAssetFormatSupport)
  781. {
  782. FToolMenuSection& FormatActionsSection = Menu->AddSection("AssetContextTextAssetFormatActions", LOCTEXT("AssetContextTextAssetFormatActionsHeading", "Text Assets"));
  783. {
  784. FormatActionsSection.AddMenuEntry(
  785. "ExportToTextFormat",
  786. LOCTEXT("ExportToTextFormat", "Export to text format"),
  787. LOCTEXT("ExportToTextFormatTooltip", "Exports the selected asset(s) to the experimental text asset format"),
  788. FSlateIcon(),
  789. FUIAction(FExecuteAction::CreateSP(this, &FAssetContextMenu::ExportSelectedAssetsToText))
  790. );
  791. FormatActionsSection.AddMenuEntry(
  792. "ViewSelectedAssetAsText",
  793. LOCTEXT("ViewSelectedAssetAsText", "View as text"),
  794. LOCTEXT("ViewSelectedAssetAsTextTooltip", "Opens a window showing the selected asset in text format"),
  795. FSlateIcon(),
  796. FUIAction(FExecuteAction::CreateSP(this, &FAssetContextMenu::ViewSelectedAssetAsText),
  797. FCanExecuteAction::CreateSP(this, &FAssetContextMenu::CanViewSelectedAssetAsText))
  798. );
  799. FormatActionsSection.AddMenuEntry(
  800. "ViewSelectedAssetAsText",
  801. LOCTEXT("TextFormatRountrip", "Run Text Asset Roundtrip"),
  802. LOCTEXT("TextFormatRountripTooltip", "Save the select asset backwards or forwards between text and binary formats and check for determinism"),
  803. FSlateIcon(),
  804. FUIAction(FExecuteAction::CreateSP(this, &FAssetContextMenu::DoTextFormatRoundtrip))
  805. );
  806. }
  807. }
  808. #endif
  809. }
  810. void FAssetContextMenu::ExportSelectedAssetsToText()
  811. {
  812. #if ECB_LEGACY
  813. FString FailedPackage;
  814. for (const FExtAssetData& Asset : SelectedAssets)
  815. {
  816. UPackage* Package = Asset.GetPackage();
  817. FString Filename = FPackageName::LongPackageNameToFilename(Package->GetPathName(), FPackageName::GetTextAssetPackageExtension());
  818. if (!SavePackageHelper(Package, Filename))
  819. {
  820. FailedPackage = Package->GetPathName();
  821. break;
  822. }
  823. }
  824. if (FailedPackage.Len() > 0)
  825. {
  826. FNotificationInfo Info(LOCTEXT("ExportedTextAssetFailed", "Exported selected asset(s) failed"));
  827. Info.ExpireDuration = 3.0f;
  828. FSlateNotificationManager::Get().AddNotification(Info);
  829. }
  830. else
  831. {
  832. FNotificationInfo Info(LOCTEXT("ExportedTextAssetsSuccessfully", "Exported selected asset(s) successfully"));
  833. Info.ExpireDuration = 3.0f;
  834. FSlateNotificationManager::Get().AddNotification(Info);
  835. }
  836. #endif
  837. }
  838. bool FAssetContextMenu::CanExportSelectedAssetsToText() const
  839. {
  840. return true;
  841. }
  842. bool FAssetContextMenu::CanExecuteAssetActions() const
  843. {
  844. return !bAtLeastOneClassSelected;
  845. }
  846. void FAssetContextMenu::ExecuteFindInAssetTree(TArray<FName> InAssets)
  847. {
  848. #if ECB_LEGACY
  849. FAssetRegistryModule& AssetRegistryModule = FModuleManager::LoadModuleChecked<FAssetRegistryModule>(TEXT("AssetRegistry"));
  850. FARFilter ARFilter;
  851. ARFilter.ObjectPaths = MoveTemp(InAssets);
  852. TArray<FExtAssetData> FoundLocalizedAssetData;
  853. FExtContentBrowserSingleton::GetAssetRegistry().GetAssets(ARFilter, FoundLocalizedAssetData);
  854. OnFindInAssetTreeRequested.ExecuteIfBound(FoundLocalizedAssetData);
  855. #endif
  856. }
  857. void FAssetContextMenu::ExecuteOpenEditorsForAssets(TArray<FName> InAssets)
  858. {
  859. GEditor->GetEditorSubsystem<UAssetEditorSubsystem>()->OpenEditorsForAssets(InAssets);
  860. }
  861. bool FAssetContextMenu::AddReferenceMenuOptions(UToolMenu* Menu)
  862. {
  863. #if ECB_LEGACY
  864. MenuBuilder.BeginSection("AssetContExtDependencys", LOCTEXT("ReferencesMenuHeading", "References"));
  865. {
  866. MenuBuilder.AddMenuEntry(
  867. LOCTEXT("CopyReference", "Copy Reference"),
  868. LOCTEXT("CopyReferenceTooltip", "Copies reference paths for the selected assets to the clipboard."),
  869. FSlateIcon(),
  870. FUIAction( FExecuteAction::CreateSP( this, &FAssetContextMenu::ExecuteCopyReference ) )
  871. );
  872. }
  873. MenuBuilder.EndSection();
  874. #endif
  875. return true;
  876. }
  877. bool FAssetContextMenu::AddCopyMenuOptions(UToolMenu* Menu)
  878. {
  879. FToolMenuSection& Section = Menu->AddSection("AssetContextCopy", LOCTEXT("CoopyMenuHeading", "Copy"));
  880. {
  881. Section.AddMenuEntry(
  882. "CopyFilePath",
  883. LOCTEXT("CopyFilePath", "Copy File Path"),
  884. LOCTEXT("CopyFilePathTooltip", "Copies the file paths of the selected assets to the clipboard."),
  885. FSlateIcon(),
  886. FUIAction(
  887. FExecuteAction::CreateSP(this, &FAssetContextMenu::ExecuteCopyFilePath),
  888. FCanExecuteAction::CreateSP(this, &FAssetContextMenu::CanCopyFilePath)
  889. )
  890. );
  891. }
  892. return true;
  893. }
  894. bool FAssetContextMenu::AddAssetTypeMenuOptions(UToolMenu* Menu, bool bHasObjectsSelected)
  895. {
  896. bool bAnyTypeOptions = false;
  897. #if ECB_LEGACY
  898. if (bHasObjectsSelected)
  899. {
  900. // Label "GetAssetActions" section
  901. UExtContentBrowserAssetContextMenuContext* Context = Menu->FindContext<UExtContentBrowserAssetContextMenuContext>();
  902. if (Context)
  903. {
  904. FToolMenuSection& Section = Menu->FindOrAddSection("GetAssetActions");
  905. if (Context->CommonAssetTypeActions.IsValid())
  906. {
  907. Section.Label = FText::Format(NSLOCTEXT("AssetTools", "AssetSpecificOptionsMenuHeading", "{0} Actions"), Context->CommonAssetTypeActions.Pin()->GetName());
  908. }
  909. else if (Context->CommonClass)
  910. {
  911. Section.Label = FText::Format(NSLOCTEXT("AssetTools", "AssetSpecificOptionsMenuHeading", "{0} Actions"), FText::FromName(Context->CommonClass->GetFName()));
  912. }
  913. else
  914. {
  915. Section.Label = FText::Format(NSLOCTEXT("AssetTools", "AssetSpecificOptionsMenuHeading", "{0} Actions"), FText::FromString(TEXT("Asset")));
  916. }
  917. bAnyTypeOptions = true;
  918. }
  919. }
  920. #endif
  921. return bAnyTypeOptions;
  922. }
  923. bool FAssetContextMenu::AddCollectionMenuOptions(FMenuBuilder& MenuBuilder)
  924. {
  925. #if ECB_LEGACY
  926. class FManageCollectionsContextMenu
  927. {
  928. public:
  929. static void CreateManageCollectionsSubMenu(FMenuBuilder& SubMenuBuilder, TSharedRef<FCollectionAssetManagement> QuickAssetManagement)
  930. {
  931. FCollectionManagerModule& CollectionManagerModule = FCollectionManagerModule::GetModule();
  932. TArray<FCollectionNameType> AvailableCollections;
  933. CollectionManagerModule.Get().GetRootCollections(AvailableCollections);
  934. CreateManageCollectionsSubMenu(SubMenuBuilder, QuickAssetManagement, MoveTemp(AvailableCollections));
  935. }
  936. static void CreateManageCollectionsSubMenu(FMenuBuilder& SubMenuBuilder, TSharedRef<FCollectionAssetManagement> QuickAssetManagement, TArray<FCollectionNameType> AvailableCollections)
  937. {
  938. FCollectionManagerModule& CollectionManagerModule = FCollectionManagerModule::GetModule();
  939. AvailableCollections.Sort([](const FCollectionNameType& One, const FCollectionNameType& Two) -> bool
  940. {
  941. return One.Name.LexicalLess(Two.Name);
  942. });
  943. for (const FCollectionNameType& AvailableCollection : AvailableCollections)
  944. {
  945. // Never display system collections
  946. if (AvailableCollection.Type == ECollectionShareType::CST_System)
  947. {
  948. continue;
  949. }
  950. // Can only manage assets for static collections
  951. ECollectionStorageMode::Type StorageMode = ECollectionStorageMode::Static;
  952. CollectionManagerModule.Get().GetCollectionStorageMode(AvailableCollection.Name, AvailableCollection.Type, StorageMode);
  953. if (StorageMode != ECollectionStorageMode::Static)
  954. {
  955. continue;
  956. }
  957. TArray<FCollectionNameType> AvailableChildCollections;
  958. CollectionManagerModule.Get().GetChildCollections(AvailableCollection.Name, AvailableCollection.Type, AvailableChildCollections);
  959. if (AvailableChildCollections.Num() > 0)
  960. {
  961. SubMenuBuilder.AddSubMenu(
  962. FText::FromName(AvailableCollection.Name),
  963. FText::GetEmpty(),
  964. FNewMenuDelegate::CreateStatic(&FManageCollectionsContextMenu::CreateManageCollectionsSubMenu, QuickAssetManagement, AvailableChildCollections),
  965. FUIAction(
  966. FExecuteAction::CreateStatic(&FManageCollectionsContextMenu::OnCollectionClicked, QuickAssetManagement, AvailableCollection),
  967. FCanExecuteAction::CreateStatic(&FManageCollectionsContextMenu::IsCollectionEnabled, QuickAssetManagement, AvailableCollection),
  968. FGetActionCheckState::CreateStatic(&FManageCollectionsContextMenu::GetCollectionCheckState, QuickAssetManagement, AvailableCollection)
  969. ),
  970. NAME_None,
  971. EUserInterfaceActionType::ToggleButton,
  972. false,
  973. FSlateIcon(FAppStyle::GetStyleSetName(), ECollectionShareType::GetIconStyleName(AvailableCollection.Type))
  974. );
  975. }
  976. else
  977. {
  978. SubMenuBuilder.AddMenuEntry(
  979. FText::FromName(AvailableCollection.Name),
  980. FText::GetEmpty(),
  981. FSlateIcon(FAppStyle::GetStyleSetName(), ECollectionShareType::GetIconStyleName(AvailableCollection.Type)),
  982. FUIAction(
  983. FExecuteAction::CreateStatic(&FManageCollectionsContextMenu::OnCollectionClicked, QuickAssetManagement, AvailableCollection),
  984. FCanExecuteAction::CreateStatic(&FManageCollectionsContextMenu::IsCollectionEnabled, QuickAssetManagement, AvailableCollection),
  985. FGetActionCheckState::CreateStatic(&FManageCollectionsContextMenu::GetCollectionCheckState, QuickAssetManagement, AvailableCollection)
  986. ),
  987. NAME_None,
  988. EUserInterfaceActionType::ToggleButton
  989. );
  990. }
  991. }
  992. }
  993. private:
  994. static bool IsCollectionEnabled(TSharedRef<FCollectionAssetManagement> QuickAssetManagement, FCollectionNameType InCollectionKey)
  995. {
  996. return QuickAssetManagement->IsCollectionEnabled(InCollectionKey);
  997. }
  998. static ECheckBoxState GetCollectionCheckState(TSharedRef<FCollectionAssetManagement> QuickAssetManagement, FCollectionNameType InCollectionKey)
  999. {
  1000. return QuickAssetManagement->GetCollectionCheckState(InCollectionKey);
  1001. }
  1002. static void OnCollectionClicked(TSharedRef<FCollectionAssetManagement> QuickAssetManagement, FCollectionNameType InCollectionKey)
  1003. {
  1004. // The UI actions don't give you the new check state, so we need to emulate the behavior of SCheckBox
  1005. // Basically, checked will transition to unchecked (removing items), and anything else will transition to checked (adding items)
  1006. if (GetCollectionCheckState(QuickAssetManagement, InCollectionKey) == ECheckBoxState::Checked)
  1007. {
  1008. QuickAssetManagement->RemoveCurrentAssetsFromCollection(InCollectionKey);
  1009. }
  1010. else
  1011. {
  1012. QuickAssetManagement->AddCurrentAssetsToCollection(InCollectionKey);
  1013. }
  1014. }
  1015. };
  1016. bool bHasAddedItems = false;
  1017. FCollectionManagerModule& CollectionManagerModule = FCollectionManagerModule::GetModule();
  1018. MenuBuilder.BeginSection("AssetContextCollections", LOCTEXT("AssetCollectionOptionsMenuHeading", "Collections"));
  1019. // Show a sub-menu that allows you to quickly add or remove the current asset selection from the available collections
  1020. if (CollectionManagerModule.Get().HasCollections())
  1021. {
  1022. TSharedRef<FCollectionAssetManagement> QuickAssetManagement = MakeShareable(new FCollectionAssetManagement());
  1023. QuickAssetManagement->SetCurrentAssets(SelectedAssets);
  1024. MenuBuilder.AddSubMenu(
  1025. LOCTEXT("ManageCollections", "Manage Collections"),
  1026. LOCTEXT("ManageCollections_ToolTip", "Manage the collections that the selected asset(s) belong to."),
  1027. FNewMenuDelegate::CreateStatic(&FManageCollectionsContextMenu::CreateManageCollectionsSubMenu, QuickAssetManagement)
  1028. );
  1029. bHasAddedItems = true;
  1030. }
  1031. // "Remove from collection" (only display option if exactly one collection is selected)
  1032. if ( SourcesData.Collections.Num() == 1 && !SourcesData.IsDynamicCollection() )
  1033. {
  1034. MenuBuilder.AddMenuEntry(
  1035. FText::Format(LOCTEXT("RemoveFromCollectionFmt", "Remove From {0}"), FText::FromName(SourcesData.Collections[0].Name)),
  1036. LOCTEXT("RemoveFromCollection_ToolTip", "Removes the selected asset from the current collection."),
  1037. FSlateIcon(),
  1038. FUIAction(
  1039. FExecuteAction::CreateSP( this, &FAssetContextMenu::ExecuteRemoveFromCollection ),
  1040. FCanExecuteAction::CreateSP( this, &FAssetContextMenu::CanExecuteRemoveFromCollection )
  1041. )
  1042. );
  1043. bHasAddedItems = true;
  1044. }
  1045. MenuBuilder.EndSection();
  1046. return bHasAddedItems;
  1047. #endif
  1048. return false;
  1049. }
  1050. bool FAssetContextMenu::AreImportedAssetActionsVisible() const
  1051. {
  1052. FAssetToolsModule& AssetToolsModule = FModuleManager::Get().LoadModuleChecked<FAssetToolsModule>("AssetTools");
  1053. // Check that all of the selected assets are imported
  1054. for (auto& SelectedAsset : SelectedAssets)
  1055. {
  1056. auto AssetClass = SelectedAsset.GetClass();
  1057. if (AssetClass)
  1058. {
  1059. auto AssetTypeActions = AssetToolsModule.Get().GetAssetTypeActionsForClass(AssetClass).Pin();
  1060. if (!AssetTypeActions.IsValid() || !AssetTypeActions->IsImportedAsset())
  1061. {
  1062. return false;
  1063. }
  1064. }
  1065. }
  1066. return true;
  1067. }
  1068. bool FAssetContextMenu::CanExecuteImportedAssetActions(const TArray<FString> ResolvedFilePaths) const
  1069. {
  1070. // Verify that all the file paths are legitimate
  1071. for (const auto& SourceFilePath : ResolvedFilePaths)
  1072. {
  1073. if (!SourceFilePath.Len() || IFileManager::Get().FileSize(*SourceFilePath) == INDEX_NONE)
  1074. {
  1075. return false;
  1076. }
  1077. }
  1078. return true;
  1079. }
  1080. void FAssetContextMenu::ExecuteFindSourceInExplorer(const TArray<FString> ResolvedFilePaths)
  1081. {
  1082. // Open all files in the explorer
  1083. for (const auto& SourceFilePath : ResolvedFilePaths)
  1084. {
  1085. FPlatformProcess::ExploreFolder(*FPaths::GetPath(SourceFilePath));
  1086. }
  1087. }
  1088. void FAssetContextMenu::ExecuteOpenInExternalEditor(const TArray<FString> ResolvedFilePaths)
  1089. {
  1090. // Open all files in their respective editor
  1091. for (const auto& SourceFilePath : ResolvedFilePaths)
  1092. {
  1093. FPlatformProcess::LaunchFileInDefaultExternalApplication(*SourceFilePath, NULL, ELaunchVerb::Edit);
  1094. }
  1095. }
  1096. void FAssetContextMenu::GetSelectedAssetsByClass(TMap<UClass*, TArray<UObject*> >& OutSelectedAssetsByClass) const
  1097. {
  1098. // Sort all selected assets by class
  1099. for (const auto& SelectedAsset : SelectedAssets)
  1100. {
  1101. auto Asset = SelectedAsset.GetAsset();
  1102. auto AssetClass = Asset->GetClass();
  1103. if ( !OutSelectedAssetsByClass.Contains(AssetClass) )
  1104. {
  1105. OutSelectedAssetsByClass.Add(AssetClass);
  1106. }
  1107. OutSelectedAssetsByClass[AssetClass].Add(Asset);
  1108. }
  1109. }
  1110. void FAssetContextMenu::GetSelectedAssetSourceFilePaths(TArray<FString>& OutFilePaths, TArray<FString>& OutUniqueSourceFileLabels, int32 &OutValidSelectedAssetCount) const
  1111. {
  1112. OutFilePaths.Empty();
  1113. OutUniqueSourceFileLabels.Empty();
  1114. TMap<UClass*, TArray<UObject*> > SelectedAssetsByClass;
  1115. GetSelectedAssetsByClass(SelectedAssetsByClass);
  1116. FAssetToolsModule& AssetToolsModule = FModuleManager::Get().LoadModuleChecked<FAssetToolsModule>("AssetTools");
  1117. OutValidSelectedAssetCount = 0;
  1118. // Get the source file paths for the assets of each type
  1119. for (const auto& AssetsByClassPair : SelectedAssetsByClass)
  1120. {
  1121. const auto AssetTypeActions = AssetToolsModule.Get().GetAssetTypeActionsForClass(AssetsByClassPair.Key);
  1122. if (AssetTypeActions.IsValid())
  1123. {
  1124. const auto& TypeAssets = AssetsByClassPair.Value;
  1125. OutValidSelectedAssetCount += TypeAssets.Num();
  1126. TArray<FString> AssetSourcePaths;
  1127. AssetTypeActions.Pin()->GetResolvedSourceFilePaths(TypeAssets, AssetSourcePaths);
  1128. OutFilePaths.Append(AssetSourcePaths);
  1129. TArray<FString> AssetSourceLabels;
  1130. AssetTypeActions.Pin()->GetSourceFileLabels(TypeAssets, AssetSourceLabels);
  1131. for (const FString& Label : AssetSourceLabels)
  1132. {
  1133. OutUniqueSourceFileLabels.AddUnique(Label);
  1134. }
  1135. }
  1136. }
  1137. }
  1138. void FAssetContextMenu::ExecuteSyncToAssetTree()
  1139. {
  1140. #if ECB_LEGACY
  1141. // Copy this as the sync may adjust our selected assets array
  1142. const TArray<FExtAssetData> SelectedAssetsCopy = SelectedAssets;
  1143. OnFindInAssetTreeRequested.ExecuteIfBound(SelectedAssetsCopy);
  1144. #endif
  1145. }
  1146. void FAssetContextMenu::ExecuteCopyFilePath()
  1147. {
  1148. ExtContentBrowserUtils::CopyFilePathsToClipboard(SelectedAssets);
  1149. }
  1150. void FAssetContextMenu::ExecuteFindInExplorer()
  1151. {
  1152. for (int32 AssetIdx = 0; AssetIdx < SelectedAssets.Num(); ++AssetIdx)
  1153. {
  1154. #if ECB_LEGACY
  1155. const UObject* Asset = SelectedAssets[AssetIdx].GetAsset();
  1156. if (Asset)
  1157. {
  1158. FExtAssetData AssetData(Asset);
  1159. const FString PackageName = AssetData.PackageName.ToString();
  1160. static const TCHAR* ScriptString = TEXT("/Script/");
  1161. if (PackageName.StartsWith(ScriptString))
  1162. {
  1163. // Handle C++ classes specially, as FPackageName::LongPackageNameToFilename won't return the correct path in this case
  1164. const FString ModuleName = PackageName.RightChop(FCString::Strlen(ScriptString));
  1165. FString ModulePath;
  1166. if (FSourceCodeNavigation::FindModulePath(ModuleName, ModulePath))
  1167. {
  1168. FString RelativePath;
  1169. if (AssetData.GetTagValue("ModuleRelativePath", RelativePath))
  1170. {
  1171. const FString FullFilePath = FPaths::ConvertRelativePathToFull(ModulePath / (*RelativePath));
  1172. FPlatformProcess::ExploreFolder(*FullFilePath);
  1173. }
  1174. }
  1175. return;
  1176. }
  1177. const bool bIsWorldAsset = (AssetData.AssetClass == UWorld::StaticClass()->GetFName());
  1178. const FString Extension = bIsWorldAsset ? FPackageName::GetMapPackageExtension() : FPackageName::GetAssetPackageExtension();
  1179. const FString FilePath = FPackageName::LongPackageNameToFilename(PackageName, Extension);
  1180. const FString FullFilePath = FPaths::ConvertRelativePathToFull(FilePath);
  1181. FPlatformProcess::ExploreFolder(*FullFilePath);
  1182. }
  1183. #endif
  1184. FExtAssetData& AssetData = SelectedAssets[AssetIdx];
  1185. //if (AssetData.IsValid()) // Enable Explore Folder option even for Invalid Assets
  1186. {
  1187. const FString FullFilePath = AssetData.PackageFilePath.ToString();
  1188. FPlatformProcess::ExploreFolder(*FullFilePath);
  1189. }
  1190. }
  1191. }
  1192. void FAssetContextMenu::ExecuteValidateAsset()
  1193. {
  1194. if (SelectedAssets.Num() > 0)
  1195. {
  1196. FString ResultMessage;
  1197. FExtAssetValidator::ValidateDependency(SelectedAssets, &ResultMessage, /*bShowProgess*/ true);
  1198. if (SelectedAssets.Num() == 1)
  1199. {
  1200. ExtContentBrowserUtils::DisplayMessagePopup(FText::FromString(ResultMessage));
  1201. }
  1202. else
  1203. {
  1204. ExtContentBrowserUtils::NotifyMessage(FText::FromString(ResultMessage));
  1205. }
  1206. }
  1207. }
  1208. void FAssetContextMenu::ExecuteRevalidateAsset()
  1209. {
  1210. if (SelectedAssets.Num() > 0)
  1211. {
  1212. FExtAssetValidator::InValidateDependency(SelectedAssets);
  1213. ExecuteValidateAsset();
  1214. }
  1215. }
  1216. void FAssetContextMenu::ExecuteImportAsset()
  1217. {
  1218. if (SelectedAssets.Num() > 0)
  1219. {
  1220. FExtAssetImporter::ImportAssets(SelectedAssets, FUAssetImportSetting::GetSavedImportSetting());
  1221. }
  1222. }
  1223. void FAssetContextMenu::ExecuteFlatImportAsset()
  1224. {
  1225. if (SelectedAssets.Num() > 0)
  1226. {
  1227. #if ECB_TODO // todo: double check flat import a level
  1228. // Map is not supported
  1229. for (const FExtAssetData& AssetData : SelectedAssets)
  1230. {
  1231. if (AssetData.AssetClass == UWorld::StaticClass()->GetFName())
  1232. {
  1233. ExtContentBrowserUtils::DisplayMessagePopup(FText::FromString(TEXT("Map is not supporting Flat Import.")));
  1234. return;
  1235. }
  1236. }
  1237. #endif
  1238. FUAssetImportSetting ImportSetting = FUAssetImportSetting::GetFlatModeImportSetting();
  1239. FExtAssetImporter::ImportAssetsWithPathPicker(SelectedAssets, ImportSetting);
  1240. }
  1241. }
  1242. void FAssetContextMenu::ExecuteDirectCopyAsset()
  1243. {
  1244. FUAssetImportSetting ImportSetting = FUAssetImportSetting::GetDirectCopyModeImportSetting();
  1245. FExtAssetImporter::ImportAssets(SelectedAssets, ImportSetting);
  1246. }
  1247. void FAssetContextMenu::ExecuteReparseAsset()
  1248. {
  1249. if (SelectedAssets.Num() > 0 )
  1250. {
  1251. FScopedSlowTask SlowTask(SelectedAssets.Num(), LOCTEXT("ReparseAssets", "Reparse Assets.."));
  1252. SlowTask.MakeDialog();
  1253. FExtAssetRegistry& AssetRegistry = FExtContentBrowserSingleton::GetAssetRegistry();
  1254. for (FExtAssetData& AssetData : SelectedAssets)
  1255. {
  1256. SlowTask.EnterProgressFrame();
  1257. if (FExtAssetData* CachedAssetData = AssetRegistry.GetCachedAssetByFilePath(AssetData.PackageFilePath))
  1258. {
  1259. CachedAssetData->ReParse();
  1260. AssetRegistry.BroadcastAssetUpdatedEvent(*CachedAssetData);
  1261. }
  1262. }
  1263. }
  1264. }
  1265. void FAssetContextMenu::ExecuteSyncToContentBrowser()
  1266. {
  1267. if (SelectedAssets.Num() == 1)
  1268. {
  1269. FExtAssetData& AssetData = SelectedAssets[0];
  1270. if (AssetData.IsValid())
  1271. {
  1272. const bool bFound = FExtAssetDataUtil::SyncToContentBrowser(AssetData);
  1273. if (!bFound)
  1274. {
  1275. ExtContentBrowserUtils::NotifyMessage(FText::FromString(TEXT("No corresponding asset found in Content Browser.")));
  1276. }
  1277. }
  1278. }
  1279. }
  1280. void FAssetContextMenu::ExecuteCreateBlueprintUsing()
  1281. {
  1282. if(SelectedAssets.Num() == 1)
  1283. {
  1284. UObject* Asset = SelectedAssets[0].GetAsset();
  1285. FKismetEditorUtilities::CreateBlueprintUsingAsset(Asset, true);
  1286. }
  1287. }
  1288. void FAssetContextMenu::GetSelectedAssets(TArray<UObject*>& Assets, bool SkipRedirectors) const
  1289. {
  1290. for (int32 AssetIdx = 0; AssetIdx < SelectedAssets.Num(); ++AssetIdx)
  1291. {
  1292. if (SkipRedirectors && (SelectedAssets[AssetIdx].AssetClass == UObjectRedirector::StaticClass()->GetFName()))
  1293. {
  1294. // Don't operate on Redirectors
  1295. continue;
  1296. }
  1297. UObject* Object = SelectedAssets[AssetIdx].GetAsset();
  1298. if (Object)
  1299. {
  1300. Assets.Add(Object);
  1301. }
  1302. }
  1303. }
  1304. /** Generates a reference graph of the world and can then find actors referencing specified objects */
  1305. struct WorldReferenceGenerator : public FFindReferencedAssets
  1306. {
  1307. void BuildReferencingData()
  1308. {
  1309. MarkAllObjects();
  1310. const int32 MaxRecursionDepth = 0;
  1311. const bool bIncludeClasses = true;
  1312. const bool bIncludeDefaults = false;
  1313. const bool bReverseReferenceGraph = true;
  1314. UWorld* World = GWorld;
  1315. // Generate the reference graph for the world
  1316. FReferencedAssets* WorldReferencer = new(Referencers)FReferencedAssets(World);
  1317. FFindAssetsArchive(World, WorldReferencer->AssetList, &ReferenceGraph, MaxRecursionDepth, bIncludeClasses, bIncludeDefaults, bReverseReferenceGraph);
  1318. // Also include all the streaming levels in the results
  1319. for (ULevelStreaming* StreamingLevel : World->GetStreamingLevels())
  1320. {
  1321. if (StreamingLevel)
  1322. {
  1323. if (ULevel* Level = StreamingLevel->GetLoadedLevel())
  1324. {
  1325. // Generate the reference graph for each streamed in level
  1326. FReferencedAssets* LevelReferencer = new(Referencers) FReferencedAssets(Level);
  1327. FFindAssetsArchive(Level, LevelReferencer->AssetList, &ReferenceGraph, MaxRecursionDepth, bIncludeClasses, bIncludeDefaults, bReverseReferenceGraph);
  1328. }
  1329. }
  1330. }
  1331. TArray<UObject*> ReferencedObjects;
  1332. // Special case for blueprints
  1333. for (AActor* Actor : FActorRange(World))
  1334. {
  1335. ReferencedObjects.Reset();
  1336. Actor->GetReferencedContentObjects(ReferencedObjects);
  1337. for (UObject* Reference : ReferencedObjects)
  1338. {
  1339. auto& Objects = ReferenceGraph.FindOrAdd(Reference);
  1340. Objects.Add(Actor);
  1341. }
  1342. }
  1343. }
  1344. void MarkAllObjects()
  1345. {
  1346. // Mark all objects so we don't get into an endless recursion
  1347. for (FThreadSafeObjectIterator It; It; ++It)
  1348. {
  1349. It->Mark(OBJECTMARK_TagExp);
  1350. }
  1351. }
  1352. void Generate(const UObject* AssetToFind, TSet<const UObject*>& OutObjects)
  1353. {
  1354. // Don't examine visited objects
  1355. if (!AssetToFind->HasAnyMarks(OBJECTMARK_TagExp))
  1356. {
  1357. return;
  1358. }
  1359. AssetToFind->UnMark(OBJECTMARK_TagExp);
  1360. // Return once we find a parent object that is an actor
  1361. if (AssetToFind->IsA(AActor::StaticClass()))
  1362. {
  1363. OutObjects.Add(AssetToFind);
  1364. return;
  1365. }
  1366. // Traverse the reference graph looking for actor objects
  1367. auto* ReferencingObjects = ReferenceGraph.Find(AssetToFind);
  1368. if (ReferencingObjects)
  1369. {
  1370. for (const auto& SetIt : *ReferencingObjects)
  1371. {
  1372. Generate(SetIt, OutObjects);
  1373. }
  1374. }
  1375. }
  1376. };
  1377. void FAssetContextMenu::ExecuteFindAssetInWorld()
  1378. {
  1379. TArray<UObject*> AssetsToFind;
  1380. const bool SkipRedirectors = true;
  1381. GetSelectedAssets(AssetsToFind, SkipRedirectors);
  1382. const bool NoteSelectionChange = true;
  1383. const bool DeselectBSPSurfs = true;
  1384. const bool WarnAboutManyActors = false;
  1385. GEditor->SelectNone(NoteSelectionChange, DeselectBSPSurfs, WarnAboutManyActors);
  1386. if (AssetsToFind.Num() > 0)
  1387. {
  1388. FScopedSlowTask SlowTask(2 + AssetsToFind.Num(), NSLOCTEXT("AssetContextMenu", "FindAssetInWorld", "Finding actors that use this asset..."));
  1389. SlowTask.MakeDialog();
  1390. CollectGarbage(GARBAGE_COLLECTION_KEEPFLAGS);
  1391. TSet<const UObject*> OutObjects;
  1392. WorldReferenceGenerator ObjRefGenerator;
  1393. SlowTask.EnterProgressFrame();
  1394. ObjRefGenerator.BuildReferencingData();
  1395. for (UObject* AssetToFind : AssetsToFind)
  1396. {
  1397. SlowTask.EnterProgressFrame();
  1398. ObjRefGenerator.MarkAllObjects();
  1399. ObjRefGenerator.Generate(AssetToFind, OutObjects);
  1400. }
  1401. SlowTask.EnterProgressFrame();
  1402. if (OutObjects.Num() > 0)
  1403. {
  1404. const bool InSelected = true;
  1405. const bool Notify = false;
  1406. // Select referencing actors
  1407. for (const UObject* Object : OutObjects)
  1408. {
  1409. GEditor->SelectActor(const_cast<AActor*>(CastChecked<AActor>(Object)), InSelected, Notify);
  1410. }
  1411. GEditor->NoteSelectionChange();
  1412. }
  1413. else
  1414. {
  1415. FNotificationInfo Info(LOCTEXT("NoReferencingActorsFound", "No actors found."));
  1416. Info.ExpireDuration = 3.0f;
  1417. FSlateNotificationManager::Get().AddNotification(Info);
  1418. }
  1419. }
  1420. }
  1421. void FAssetContextMenu::ExecutePropertyMatrix()
  1422. {
  1423. TArray<UObject*> ObjectsForPropertiesMenu;
  1424. const bool SkipRedirectors = true;
  1425. GetSelectedAssets(ObjectsForPropertiesMenu, SkipRedirectors);
  1426. if ( ObjectsForPropertiesMenu.Num() > 0 )
  1427. {
  1428. FPropertyEditorModule& PropertyEditorModule = FModuleManager::LoadModuleChecked<FPropertyEditorModule>( "PropertyEditor" );
  1429. PropertyEditorModule.CreatePropertyEditorToolkit(TSharedPtr<IToolkitHost>(), ObjectsForPropertiesMenu);
  1430. }
  1431. }
  1432. void FAssetContextMenu::ExecuteShowAssetMetaData()
  1433. {
  1434. for (const FExtAssetData& AssetData : SelectedAssets)
  1435. {
  1436. UObject* Asset = AssetData.GetAsset();
  1437. if (Asset)
  1438. {
  1439. TMap<FName, FString>* TagValues = UMetaData::GetMapForObject(Asset);
  1440. if (TagValues)
  1441. {
  1442. // Create and display a resizable window to display the MetaDataView for each asset with metadata
  1443. FString Title = FString::Printf(TEXT("Metadata: %s"), *AssetData.AssetName.ToString());
  1444. TSharedPtr< SWindow > Window = SNew(SWindow)
  1445. .Title(FText::FromString(Title))
  1446. .SupportsMaximize(false)
  1447. .SupportsMinimize(false)
  1448. .MinWidth(500.0f)
  1449. .MinHeight(250.0f)
  1450. [
  1451. SNew(SBorder)
  1452. .Padding(4.f)
  1453. .BorderImage(FAppStyle::GetBrush("ToolPanel.GroupBorder"))
  1454. [
  1455. SNew(SMetaDataView, *TagValues)
  1456. ]
  1457. ];
  1458. FSlateApplication::Get().AddWindow(Window.ToSharedRef());
  1459. }
  1460. }
  1461. }
  1462. }
  1463. void FAssetContextMenu::ExecuteEditAsset()
  1464. {
  1465. TMap<UClass*, TArray<UObject*> > SelectedAssetsByClass;
  1466. GetSelectedAssetsByClass(SelectedAssetsByClass);
  1467. // Open
  1468. for (const auto& AssetsByClassPair : SelectedAssetsByClass)
  1469. {
  1470. const auto& TypeAssets = AssetsByClassPair.Value;
  1471. GEditor->GetEditorSubsystem<UAssetEditorSubsystem>()->OpenEditorForAssets(TypeAssets);
  1472. }
  1473. }
  1474. void FAssetContextMenu::ExecuteSaveAsset()
  1475. {
  1476. TArray<UPackage*> PackagesToSave;
  1477. GetSelectedPackages(PackagesToSave);
  1478. const bool bCheckDirty = false;
  1479. const bool bPromptToSave = false;
  1480. FEditorFileUtils::PromptForCheckoutAndSave(PackagesToSave, bCheckDirty, bPromptToSave);
  1481. }
  1482. void FAssetContextMenu::ExecuteDiffSelected() const
  1483. {
  1484. if (SelectedAssets.Num() >= 2)
  1485. {
  1486. UObject* FirstObjectSelected = SelectedAssets[0].GetAsset();
  1487. UObject* SecondObjectSelected = SelectedAssets[1].GetAsset();
  1488. if ((FirstObjectSelected != NULL) && (SecondObjectSelected != NULL))
  1489. {
  1490. // Load the asset registry module
  1491. FAssetToolsModule& AssetToolsModule = FModuleManager::GetModuleChecked<FAssetToolsModule>("AssetTools");
  1492. FRevisionInfo CurrentRevision;
  1493. CurrentRevision.Revision = TEXT("");
  1494. AssetToolsModule.Get().DiffAssets(FirstObjectSelected, SecondObjectSelected, CurrentRevision, CurrentRevision);
  1495. }
  1496. }
  1497. }
  1498. bool FAssetContextMenu::CanExecuteReload() const
  1499. {
  1500. #if ECB_LEGACY
  1501. TArray< FExtAssetData > AssetViewSelectedAssets = AssetView.Pin()->GetSelectedAssets();
  1502. TArray< FString > SelectedFolders = AssetView.Pin()->GetSelectedFolders();
  1503. int32 NumAssetItems, NumClassItems;
  1504. ContentBrowserUtils::CountItemTypes(AssetViewSelectedAssets, NumAssetItems, NumClassItems);
  1505. int32 NumAssetPaths, NumClassPaths;
  1506. ContentBrowserUtils::CountPathTypes(SelectedFolders, NumAssetPaths, NumClassPaths);
  1507. bool bHasSelectedCollections = false;
  1508. for (const FString& SelectedFolder : SelectedFolders)
  1509. {
  1510. if (ContentBrowserUtils::IsCollectionPath(SelectedFolder))
  1511. {
  1512. bHasSelectedCollections = true;
  1513. break;
  1514. }
  1515. }
  1516. // We can't reload classes, or folders containing classes, or any collection folders
  1517. return ((NumAssetItems > 0 && NumClassItems == 0) || (NumAssetPaths > 0 && NumClassPaths == 0)) && !bHasSelectedCollections;
  1518. #endif
  1519. return false;
  1520. }
  1521. void FAssetContextMenu::ExecuteReload()
  1522. {
  1523. #if ECB_LEGACY
  1524. // Don't allow asset reload during PIE
  1525. if (GIsEditor)
  1526. {
  1527. UEditorEngine* Editor = GEditor;
  1528. FWorldContext* PIEWorldContext = GEditor->GetPIEWorldContext();
  1529. if (PIEWorldContext)
  1530. {
  1531. FNotificationInfo Notification(LOCTEXT("CannotReloadAssetInPIE", "Assets cannot be reloaded while in PIE."));
  1532. Notification.ExpireDuration = 3.0f;
  1533. FSlateNotificationManager::Get().AddNotification(Notification);
  1534. return;
  1535. }
  1536. }
  1537. TArray<FExtAssetData> AssetViewSelectedAssets = AssetView.Pin()->GetSelectedAssets();
  1538. if (AssetViewSelectedAssets.Num() > 0)
  1539. {
  1540. TArray<UPackage*> PackagesToReload;
  1541. for (auto AssetIt = AssetViewSelectedAssets.CreateConstIterator(); AssetIt; ++AssetIt)
  1542. {
  1543. const FExtAssetData& AssetData = *AssetIt;
  1544. if (AssetData.AssetClass == UObjectRedirector::StaticClass()->GetFName())
  1545. {
  1546. // Don't operate on Redirectors
  1547. continue;
  1548. }
  1549. if (AssetData.AssetClass == UUserDefinedStruct::StaticClass()->GetFName())
  1550. {
  1551. FNotificationInfo Notification(LOCTEXT("CannotReloadUserStruct", "User created structures cannot be safely reloaded."));
  1552. Notification.ExpireDuration = 3.0f;
  1553. FSlateNotificationManager::Get().AddNotification(Notification);
  1554. continue;
  1555. }
  1556. if (AssetData.AssetClass == UUserDefinedEnum::StaticClass()->GetFName())
  1557. {
  1558. FNotificationInfo Notification(LOCTEXT("CannotReloadUserEnum", "User created enumerations cannot be safely reloaded."));
  1559. Notification.ExpireDuration = 3.0f;
  1560. FSlateNotificationManager::Get().AddNotification(Notification);
  1561. continue;
  1562. }
  1563. PackagesToReload.AddUnique(AssetData.GetPackage());
  1564. }
  1565. if (PackagesToReload.Num() > 0)
  1566. {
  1567. UPackageTools::ReloadPackages(PackagesToReload);
  1568. }
  1569. }
  1570. #endif
  1571. }
  1572. void FAssetContextMenu::ExecuteMigrateAsset()
  1573. {
  1574. // Get a list of package names for input into MigratePackages
  1575. TArray<FName> PackageNames;
  1576. PackageNames.Reserve(SelectedAssets.Num());
  1577. for (int32 AssetIdx = 0; AssetIdx < SelectedAssets.Num(); ++AssetIdx)
  1578. {
  1579. PackageNames.Add(SelectedAssets[AssetIdx].PackageName);
  1580. }
  1581. FAssetToolsModule& AssetToolsModule = FModuleManager::Get().LoadModuleChecked<FAssetToolsModule>("AssetTools");
  1582. AssetToolsModule.Get().MigratePackages( PackageNames );
  1583. }
  1584. void FAssetContextMenu::ExecuteGoToCodeForAsset(UClass* SelectedClass)
  1585. {
  1586. if (SelectedClass)
  1587. {
  1588. FString ClassHeaderPath;
  1589. if( FSourceCodeNavigation::FindClassHeaderPath( SelectedClass, ClassHeaderPath ) && IFileManager::Get().FileSize( *ClassHeaderPath ) != INDEX_NONE )
  1590. {
  1591. const FString AbsoluteHeaderPath = IFileManager::Get().ConvertToAbsolutePathForExternalAppForRead(*ClassHeaderPath);
  1592. FSourceCodeNavigation::OpenSourceFile( AbsoluteHeaderPath );
  1593. }
  1594. }
  1595. }
  1596. void FAssetContextMenu::ExecuteGoToDocsForAsset(UClass* SelectedClass)
  1597. {
  1598. ExecuteGoToDocsForAsset(SelectedClass, FString());
  1599. }
  1600. void FAssetContextMenu::ExecuteGoToDocsForAsset(UClass* SelectedClass, const FString ExcerptSection)
  1601. {
  1602. if (SelectedClass)
  1603. {
  1604. FString DocumentationLink = FEditorClassUtils::GetDocumentationLink(SelectedClass, ExcerptSection);
  1605. if (!DocumentationLink.IsEmpty())
  1606. {
  1607. IDocumentation::Get()->Open(DocumentationLink, FDocumentationSourceInfo(TEXT("cb_docs")));
  1608. }
  1609. }
  1610. }
  1611. void FAssetContextMenu::ExecuteCopyReference()
  1612. {
  1613. //ContentBrowserUtils::CopyAssetReferencesToClipboard(SelectedAssets);
  1614. }
  1615. void FAssetContextMenu::ExecuteCopyTextToClipboard(FString InText)
  1616. {
  1617. FPlatformApplicationMisc::ClipboardCopy(*InText);
  1618. }
  1619. void FAssetContextMenu::ExecuteShowLocalizationCache(const FString InPackageFilename)
  1620. {
  1621. FString CachedLocalizationId;
  1622. TArray<FGatherableTextData> GatherableTextDataArray;
  1623. // Read the localization data from the cache in the package header
  1624. {
  1625. TUniquePtr<FArchive> FileReader(IFileManager::Get().CreateFileReader(*InPackageFilename));
  1626. if (FileReader)
  1627. {
  1628. // Read package file summary from the file
  1629. FPackageFileSummary PackageFileSummary;
  1630. *FileReader << PackageFileSummary;
  1631. CachedLocalizationId = PackageFileSummary.LocalizationId;
  1632. if (PackageFileSummary.GatherableTextDataOffset > 0)
  1633. {
  1634. FileReader->Seek(PackageFileSummary.GatherableTextDataOffset);
  1635. GatherableTextDataArray.SetNum(PackageFileSummary.GatherableTextDataCount);
  1636. for (int32 GatherableTextDataIndex = 0; GatherableTextDataIndex < PackageFileSummary.GatherableTextDataCount; ++GatherableTextDataIndex)
  1637. {
  1638. *FileReader << GatherableTextDataArray[GatherableTextDataIndex];
  1639. }
  1640. }
  1641. }
  1642. }
  1643. // Convert the gathered text array into a readable format
  1644. FString LocalizationCacheStr = FString::Printf(TEXT("Package: %s"), *CachedLocalizationId);
  1645. for (const FGatherableTextData& GatherableTextData : GatherableTextDataArray)
  1646. {
  1647. if (LocalizationCacheStr.Len() > 0)
  1648. {
  1649. LocalizationCacheStr += TEXT("\n\n");
  1650. }
  1651. FString KeysStr;
  1652. FString EditorOnlyKeysStr;
  1653. for (const FTextSourceSiteContext& TextSourceSiteContext : GatherableTextData.SourceSiteContexts)
  1654. {
  1655. FString* KeysStrPtr = TextSourceSiteContext.IsEditorOnly ? &EditorOnlyKeysStr : &KeysStr;
  1656. if (KeysStrPtr->Len() > 0)
  1657. {
  1658. *KeysStrPtr += TEXT(", ");
  1659. }
  1660. *KeysStrPtr += TextSourceSiteContext.KeyName;
  1661. }
  1662. LocalizationCacheStr += FString::Printf(TEXT("Namespace: %s\n"), *GatherableTextData.NamespaceName);
  1663. if (KeysStr.Len() > 0)
  1664. {
  1665. LocalizationCacheStr += FString::Printf(TEXT("Keys: %s\n"), *KeysStr);
  1666. }
  1667. if (EditorOnlyKeysStr.Len() > 0)
  1668. {
  1669. LocalizationCacheStr += FString::Printf(TEXT("Keys (Editor-Only): %s\n"), *EditorOnlyKeysStr);
  1670. }
  1671. LocalizationCacheStr += FString::Printf(TEXT("Source: %s"), *GatherableTextData.SourceData.SourceString);
  1672. }
  1673. // Generate a message box for the result
  1674. SGenericDialogWidget::OpenDialog(LOCTEXT("LocalizationCache", "Localization Cache"),
  1675. SNew(SBox)
  1676. .MaxDesiredWidth(800.0f)
  1677. .MaxDesiredHeight(400.0f)
  1678. [
  1679. SNew(SMultiLineEditableTextBox)
  1680. .IsReadOnly(true)
  1681. .AutoWrapText(true)
  1682. .Text(FText::AsCultureInvariant(LocalizationCacheStr))
  1683. ],
  1684. SGenericDialogWidget::FArguments()
  1685. .UseScrollBox(false)
  1686. );
  1687. }
  1688. void FAssetContextMenu::ExecuteDumpExport()
  1689. {
  1690. FUAssetImportSetting ImportSetting = FUAssetImportSetting::GetSandboxImportForDumpSetting();
  1691. FExtAssetImporter::ImportAssets(SelectedAssets, ImportSetting);
  1692. }
  1693. bool FAssetContextMenu::CanExecuteDumpExport() const
  1694. {
  1695. return SelectedAssets.Num() == 1;
  1696. }
  1697. void FAssetContextMenu::ExecuteExport()
  1698. {
  1699. TArray<UObject*> ObjectsToExport;
  1700. const bool SkipRedirectors = false;
  1701. GetSelectedAssets(ObjectsToExport, SkipRedirectors);
  1702. if ( ObjectsToExport.Num() > 0 )
  1703. {
  1704. FAssetToolsModule& AssetToolsModule = FModuleManager::GetModuleChecked<FAssetToolsModule>("AssetTools");
  1705. AssetToolsModule.Get().ExportAssetsWithDialog(ObjectsToExport, true);
  1706. }
  1707. }
  1708. void FAssetContextMenu::ExecuteBulkExport()
  1709. {
  1710. TArray<UObject*> ObjectsToExport;
  1711. const bool SkipRedirectors = false;
  1712. GetSelectedAssets(ObjectsToExport, SkipRedirectors);
  1713. if ( ObjectsToExport.Num() > 0 )
  1714. {
  1715. FAssetToolsModule& AssetToolsModule = FModuleManager::GetModuleChecked<FAssetToolsModule>("AssetTools");
  1716. AssetToolsModule.Get().ExportAssetsWithDialog(ObjectsToExport, false);
  1717. }
  1718. }
  1719. void FAssetContextMenu::ExecuteRemoveFromCollection()
  1720. {
  1721. if ( ensure(SourcesData.Collections.Num() == 1) )
  1722. {
  1723. TArray<FSoftObjectPath> AssetsToRemove;
  1724. for (auto AssetIt = SelectedAssets.CreateConstIterator(); AssetIt; ++AssetIt)
  1725. {
  1726. AssetsToRemove.Add((*AssetIt).GetSoftObjectPath());
  1727. }
  1728. if ( AssetsToRemove.Num() > 0 )
  1729. {
  1730. FCollectionManagerModule& CollectionManagerModule = FCollectionManagerModule::GetModule();
  1731. const FCollectionNameType& Collection = SourcesData.Collections[0];
  1732. CollectionManagerModule.Get().RemoveFromCollection(Collection.Name, Collection.Type, AssetsToRemove);
  1733. OnAssetViewRefreshRequested.ExecuteIfBound();
  1734. }
  1735. }
  1736. }
  1737. void FAssetContextMenu::ExecuteEnableSourceControl()
  1738. {
  1739. ISourceControlModule::Get().ShowLoginDialog(FSourceControlLoginClosed(), ELoginWindowMode::Modeless);
  1740. }
  1741. bool FAssetContextMenu::CanExecuteSyncToAssetTree() const
  1742. {
  1743. return SelectedAssets.Num() > 0;
  1744. }
  1745. bool FAssetContextMenu::CanExecuteSyncToContentBrowser() const
  1746. {
  1747. return SelectedAssets.Num() == 1;
  1748. }
  1749. bool FAssetContextMenu::CanCopyFilePath() const
  1750. {
  1751. return SelectedAssets.Num() > 0;
  1752. }
  1753. bool FAssetContextMenu::CanExecuteFindInExplorer() const
  1754. {
  1755. return SelectedAssets.Num() > 0;
  1756. }
  1757. bool FAssetContextMenu::CanExecuteValidateAsset() const
  1758. {
  1759. for (const auto& Asset : SelectedAssets)
  1760. {
  1761. if (Asset.CanImportFast())
  1762. {
  1763. return true;
  1764. }
  1765. }
  1766. return false;
  1767. }
  1768. bool FAssetContextMenu::CanExecuteRevalidateAsset() const
  1769. {
  1770. return CanExecuteValidateAsset();
  1771. }
  1772. bool FAssetContextMenu::CanExecuteImportAsset() const
  1773. {
  1774. return CanExecuteValidateAsset();
  1775. }
  1776. bool FAssetContextMenu::CanExecuteFlatImportAsset() const
  1777. {
  1778. return CanExecuteValidateAsset();
  1779. }
  1780. bool FAssetContextMenu::CanExecuteDirectCopyAsset() const
  1781. {
  1782. return SelectedAssets.Num() > 0;
  1783. }
  1784. bool FAssetContextMenu::CanExecuteReparseAsset() const
  1785. {
  1786. return SelectedAssets.Num() > 0;
  1787. }
  1788. bool FAssetContextMenu::CanExecuteCreateBlueprintUsing() const
  1789. {
  1790. // Only work if you have a single asset selected
  1791. if(SelectedAssets.Num() == 1)
  1792. {
  1793. UObject* Asset = SelectedAssets[0].GetAsset();
  1794. // See if we know how to make a component from this asset
  1795. TArray< TSubclassOf<UActorComponent> > ComponentClassList = FComponentAssetBrokerage::GetComponentsForAsset(Asset);
  1796. return (ComponentClassList.Num() > 0);
  1797. }
  1798. return false;
  1799. }
  1800. bool FAssetContextMenu::CanExecuteFindAssetInWorld() const
  1801. {
  1802. return bAtLeastOneNonRedirectorSelected;
  1803. }
  1804. bool FAssetContextMenu::CanExecuteProperties() const
  1805. {
  1806. return bAtLeastOneNonRedirectorSelected;
  1807. }
  1808. bool FAssetContextMenu::CanExecutePropertyMatrix(FText& OutErrorMessage) const
  1809. {
  1810. bool bResult = bAtLeastOneNonRedirectorSelected;
  1811. if (bAtLeastOneNonRedirectorSelected)
  1812. {
  1813. TArray<UObject*> ObjectsForPropertiesMenu;
  1814. const bool SkipRedirectors = true;
  1815. GetSelectedAssets(ObjectsForPropertiesMenu, SkipRedirectors);
  1816. // Ensure all Blueprints are valid.
  1817. for (UObject* Object : ObjectsForPropertiesMenu)
  1818. {
  1819. if (UBlueprint* BlueprintObj = Cast<UBlueprint>(Object))
  1820. {
  1821. if (BlueprintObj->GeneratedClass == nullptr)
  1822. {
  1823. OutErrorMessage = LOCTEXT("InvalidBlueprint", "A selected Blueprint is invalid.");
  1824. bResult = false;
  1825. break;
  1826. }
  1827. }
  1828. }
  1829. }
  1830. return bResult;
  1831. }
  1832. bool FAssetContextMenu::CanExecutePropertyMatrix() const
  1833. {
  1834. FText ErrorMessageDummy;
  1835. return CanExecutePropertyMatrix(ErrorMessageDummy);
  1836. }
  1837. FText FAssetContextMenu::GetExecutePropertyMatrixTooltip() const
  1838. {
  1839. FText ResultTooltip;
  1840. if (CanExecutePropertyMatrix(ResultTooltip))
  1841. {
  1842. ResultTooltip = LOCTEXT("PropertyMatrixTooltip", "Opens the property matrix editor for the selected assets.");
  1843. }
  1844. return ResultTooltip;
  1845. }
  1846. bool FAssetContextMenu::CanExecuteShowAssetMetaData() const
  1847. {
  1848. TArray<UObject*> ObjectsForPropertiesMenu;
  1849. const bool SkipRedirectors = true;
  1850. GetSelectedAssets(ObjectsForPropertiesMenu, SkipRedirectors);
  1851. bool bResult = false;
  1852. for (const UObject* Asset : ObjectsForPropertiesMenu)
  1853. {
  1854. if (Asset && UMetaData::GetMapForObject(Asset))
  1855. {
  1856. bResult = true;
  1857. break;
  1858. }
  1859. }
  1860. return bResult;
  1861. }
  1862. bool FAssetContextMenu::CanExecuteRename() const
  1863. {
  1864. return false;
  1865. }
  1866. bool FAssetContextMenu::CanExecuteDelete() const
  1867. {
  1868. return false;
  1869. }
  1870. bool FAssetContextMenu::CanExecuteRemoveFromCollection() const
  1871. {
  1872. return SourcesData.Collections.Num() == 1 && !SourcesData.IsDynamicCollection();
  1873. }
  1874. bool FAssetContextMenu::CanExecuteSaveAsset() const
  1875. {
  1876. if ( bAtLeastOneClassSelected )
  1877. {
  1878. return false;
  1879. }
  1880. TArray<UPackage*> Packages;
  1881. GetSelectedPackages(Packages);
  1882. // only enabled if at least one selected package is loaded at all
  1883. for (int32 PackageIdx = 0; PackageIdx < Packages.Num(); ++PackageIdx)
  1884. {
  1885. if ( Packages[PackageIdx] != NULL )
  1886. {
  1887. return true;
  1888. }
  1889. }
  1890. return false;
  1891. }
  1892. bool FAssetContextMenu::CanExecuteDiffSelected() const
  1893. {
  1894. return false;
  1895. }
  1896. bool FAssetContextMenu::CanClearCustomThumbnails() const
  1897. {
  1898. return false;
  1899. }
  1900. void FAssetContextMenu::GetSelectedPackageNames(TArray<FString>& OutPackageNames) const
  1901. {
  1902. for (int32 AssetIdx = 0; AssetIdx < SelectedAssets.Num(); ++AssetIdx)
  1903. {
  1904. OutPackageNames.Add(SelectedAssets[AssetIdx].PackageName.ToString());
  1905. }
  1906. }
  1907. void FAssetContextMenu::GetSelectedPackages(TArray<UPackage*>& OutPackages) const
  1908. {
  1909. for (int32 AssetIdx = 0; AssetIdx < SelectedAssets.Num(); ++AssetIdx)
  1910. {
  1911. UPackage* Package = FindPackage(NULL, *SelectedAssets[AssetIdx].PackageName.ToString());
  1912. if ( Package )
  1913. {
  1914. OutPackages.Add(Package);
  1915. }
  1916. }
  1917. }
  1918. #undef LOCTEXT_NAMESPACE