ExtContentBrowserSingleton.cpp 28 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908
  1. // Copyright 2017-2021 marynate. All Rights Reserved.
  2. #include "ExtContentBrowserSingleton.h"
  3. #include "ExtContentBrowserStyle.h"
  4. #include "ExtContentBrowserCommands.h"
  5. #include "SExtDependencyNode.h"
  6. #include "Textures/SlateIcon.h"
  7. #include "Misc/ConfigCacheIni.h"
  8. #include "Misc/PackageName.h"
  9. #include "Widgets/SWindow.h"
  10. #include "Widgets/Docking/SDockTab.h"
  11. #include "Widgets/Layout/SBox.h"
  12. #include "Framework/Application/SlateApplication.h"
  13. #include "Framework/Docking/WorkspaceItem.h"
  14. #include "Framework/Docking/TabManager.h"
  15. #include "Framework/MultiBox/MultiBoxBuilder.h"
  16. #include "EditorStyleSet.h"
  17. #include "Editor.h"
  18. #include "SExtContentBrowser.h"
  19. #include "WorkspaceMenuStructure.h"
  20. #include "WorkspaceMenuStructureModule.h"
  21. #include "IDocumentation.h"
  22. #include "Interfaces/IMainFrameModule.h"
  23. #include "LevelEditor.h"
  24. #include "Interfaces/IPluginManager.h"
  25. #if ECB_LEGACY
  26. #include "TutorialMetaData.h"
  27. #include "SAssetDialog.h"
  28. #include "SAssetPicker.h"
  29. #endif
  30. #if ECB_WIP_PATHPICKER
  31. #include "SPathPicker.h"
  32. #include "SCollectionPicker.h"
  33. #endif
  34. #define LOCTEXT_NAMESPACE "ExtContentBrowser"
  35. /////////////////////////////////////////////////////////////
  36. // FExtContentBrowserSingleton implementation
  37. //
  38. FExtAssetRegistry FExtContentBrowserSingleton::ExtAssetRegistry;
  39. FExtContentBrowserSingleton::FExtContentBrowserSingleton()
  40. // , SettingsStringID(0)
  41. {
  42. UExtContentBrowserSettings* ExtContentBrowserSetting = GetMutableDefault<UExtContentBrowserSettings>();
  43. #if ECB_WIP_CACHEDB
  44. ExtAssetRegistry.SwitchCacheMode();
  45. #else
  46. ExtAssetRegistry.LoadRootContentPaths();
  47. #endif
  48. #if ECB_WIP_OBJECT_THUMB_POOL
  49. if (ExtContentBrowserSetting->bUseThumbnailPool && ExtContentBrowserSetting->NumThumbnailsInPool > 0)
  50. {
  51. ThumbnailPool.Reserve(ExtContentBrowserSetting->NumThumbnailsInPool); // todo: move to setting
  52. }
  53. #endif
  54. // Style
  55. FExtContentBrowserStyle::Initialize();
  56. FExtContentBrowserStyle::ReloadTextures();
  57. RegisterMenuAndTabSpawner();
  58. RegisterCommands();
  59. {
  60. ToolbarExtender = MakeShareable(new FExtender);
  61. FLevelEditorModule& LevelEditorModule = FModuleManager::LoadModuleChecked<FLevelEditorModule>("LevelEditor");
  62. LevelEditorModule.GetToolBarExtensibilityManager()->AddExtender(ToolbarExtender);
  63. ExtContentBrowserSetting->DisplayToolbarButton = false;
  64. ToggleShowToolbarButton();
  65. }
  66. // Register Pins and nodes
  67. {
  68. ExtDependencyGraphPanelNodeFactory = MakeShareable(new FExtDependencyGraphPanelNodeFactory());
  69. FEdGraphUtilities::RegisterVisualNodeFactory(ExtDependencyGraphPanelNodeFactory);
  70. #if ECB_TODO
  71. ExtDependencyGraphPanelPinFactory = MakeShareable(new FExtDependencyGraphPanelPinFactory());
  72. FEdGraphUtilities::RegisterVisualPinFactory(ExtDependencyGraphPanelPinFactory);
  73. #endif
  74. }
  75. RegisterEditorDelegates();
  76. // Mount Sandbox
  77. MountSandbox();
  78. }
  79. FExtContentBrowserSingleton::~FExtContentBrowserSingleton()
  80. {
  81. #if ECB_LEGACY
  82. FEditorDelegates::LoadSelectedAssetsIfNeeded.RemoveAll(this);
  83. #endif
  84. if ( FSlateApplication::IsInitialized() )
  85. {
  86. for ( int32 BrowserIdx = 0; BrowserIdx < UE_ARRAY_COUNT(ContentBrowserTabIDs); BrowserIdx++ )
  87. {
  88. FGlobalTabmanager::Get()->UnregisterNomadTabSpawner( ContentBrowserTabIDs[BrowserIdx] );
  89. }
  90. }
  91. ExtAssetRegistry.Shutdown();
  92. FExtContentBrowserStyle::Shutdown();
  93. FExtContentBrowserCommands::Unregister();
  94. // Un-Register Pins and nodes
  95. {
  96. if (ExtDependencyGraphPanelNodeFactory.IsValid())
  97. {
  98. FEdGraphUtilities::UnregisterVisualNodeFactory(ExtDependencyGraphPanelNodeFactory);
  99. }
  100. #if ECB_TODO
  101. if (ExtDependencyGraphPanelPinFactory.IsValid())
  102. {
  103. FEdGraphUtilities::UnregisterVisualPinFactory(ExtDependencyGraphPanelPinFactory);
  104. }
  105. #endif
  106. }
  107. UnregisterEditorDelegates();
  108. UnMountSandbox();
  109. }
  110. #if ECB_LEGACY
  111. TSharedRef<SWidget> FContentBrowserSingleton::CreateAssetPicker(const FAssetPickerConfig& AssetPickerConfig)
  112. {
  113. return SNew( SAssetPicker )
  114. .IsEnabled( FSlateApplication::Get().GetNormalExecutionAttribute() )
  115. .AssetPickerConfig(AssetPickerConfig);
  116. }
  117. TSharedRef<SWidget> FContentBrowserSingleton::CreatePathPicker(const FPathPickerConfig& PathPickerConfig)
  118. {
  119. return SNew( SPathPicker )
  120. .IsEnabled( FSlateApplication::Get().GetNormalExecutionAttribute() )
  121. .PathPickerConfig(PathPickerConfig);
  122. }
  123. TSharedRef<class SWidget> FContentBrowserSingleton::CreateCollectionPicker(const FCollectionPickerConfig& CollectionPickerConfig)
  124. {
  125. return SNew( SCollectionPicker )
  126. .IsEnabled( FSlateApplication::Get().GetNormalExecutionAttribute() )
  127. .CollectionPickerConfig(CollectionPickerConfig);
  128. }
  129. void FContentBrowserSingleton::CreateOpenAssetDialog(const FOpenAssetDialogConfig& InConfig,
  130. const FOnAssetsChosenForOpen& InOnAssetsChosenForOpen,
  131. const FOnAssetDialogCancelled& InOnAssetDialogCancelled)
  132. {
  133. const bool bModal = false;
  134. TSharedRef<SAssetDialog> AssetDialog = SNew(SAssetDialog, InConfig);
  135. AssetDialog->SetOnAssetsChosenForOpen(InOnAssetsChosenForOpen);
  136. AssetDialog->SetOnAssetDialogCancelled(InOnAssetDialogCancelled);
  137. SharedCreateAssetDialogWindow(AssetDialog, InConfig, bModal);
  138. }
  139. TArray<FAssetData> FContentBrowserSingleton::CreateModalOpenAssetDialog(const FOpenAssetDialogConfig& InConfig)
  140. {
  141. struct FModalResults
  142. {
  143. void OnAssetsChosenForOpen(const TArray<FAssetData>& SelectedAssets)
  144. {
  145. SavedResults = SelectedAssets;
  146. }
  147. TArray<FAssetData> SavedResults;
  148. };
  149. FModalResults ModalWindowResults;
  150. FOnAssetsChosenForOpen OnAssetsChosenForOpenDelegate = FOnAssetsChosenForOpen::CreateRaw(&ModalWindowResults, &FModalResults::OnAssetsChosenForOpen);
  151. const bool bModal = true;
  152. TSharedRef<SAssetDialog> AssetDialog = SNew(SAssetDialog, InConfig);
  153. AssetDialog->SetOnAssetsChosenForOpen(OnAssetsChosenForOpenDelegate);
  154. SharedCreateAssetDialogWindow(AssetDialog, InConfig, bModal);
  155. return ModalWindowResults.SavedResults;
  156. }
  157. void FContentBrowserSingleton::CreateSaveAssetDialog(const FSaveAssetDialogConfig& InConfig,
  158. const FOnObjectPathChosenForSave& InOnObjectPathChosenForSave,
  159. const FOnAssetDialogCancelled& InOnAssetDialogCancelled)
  160. {
  161. const bool bModal = false;
  162. TSharedRef<SAssetDialog> AssetDialog = SNew(SAssetDialog, InConfig);
  163. AssetDialog->SetOnObjectPathChosenForSave(InOnObjectPathChosenForSave);
  164. AssetDialog->SetOnAssetDialogCancelled(InOnAssetDialogCancelled);
  165. SharedCreateAssetDialogWindow(AssetDialog, InConfig, bModal);
  166. }
  167. FString FContentBrowserSingleton::CreateModalSaveAssetDialog(const FSaveAssetDialogConfig& InConfig)
  168. {
  169. struct FModalResults
  170. {
  171. void OnObjectPathChosenForSave(const FString& ObjectPath)
  172. {
  173. SavedResult = ObjectPath;
  174. }
  175. FString SavedResult;
  176. };
  177. FModalResults ModalWindowResults;
  178. FOnObjectPathChosenForSave OnObjectPathChosenForSaveDelegate = FOnObjectPathChosenForSave::CreateRaw(&ModalWindowResults, &FModalResults::OnObjectPathChosenForSave);
  179. const bool bModal = true;
  180. TSharedRef<SAssetDialog> AssetDialog = SNew(SAssetDialog, InConfig);
  181. AssetDialog->SetOnObjectPathChosenForSave(OnObjectPathChosenForSaveDelegate);
  182. SharedCreateAssetDialogWindow(AssetDialog, InConfig, bModal);
  183. return ModalWindowResults.SavedResult;
  184. }
  185. bool FContentBrowserSingleton::HasPrimaryContentBrowser() const
  186. {
  187. if ( PrimaryContentBrowser.IsValid() )
  188. {
  189. // There is a primary content browser
  190. return true;
  191. }
  192. else
  193. {
  194. for (int32 BrowserIdx = 0; BrowserIdx < AllContentBrowsers.Num(); ++BrowserIdx)
  195. {
  196. if ( AllContentBrowsers[BrowserIdx].IsValid() )
  197. {
  198. // There is at least one valid content browser
  199. return true;
  200. }
  201. }
  202. // There were no valid content browsers
  203. return false;
  204. }
  205. }
  206. void FContentBrowserSingleton::FocusPrimaryContentBrowser(bool bFocusSearch)
  207. {
  208. // See if the primary content browser is still valid
  209. if ( !PrimaryContentBrowser.IsValid() )
  210. {
  211. ChooseNewPrimaryBrowser();
  212. }
  213. if ( PrimaryContentBrowser.IsValid() )
  214. {
  215. FocuSExtContentBrowser( PrimaryContentBrowser.Pin() );
  216. }
  217. else
  218. {
  219. // If we couldn't find a primary content browser, open one
  220. SummonNewBrowser();
  221. }
  222. // Do we also want to focus on the search box of the content browser?
  223. if ( bFocusSearch && PrimaryContentBrowser.IsValid() )
  224. {
  225. PrimaryContentBrowser.Pin()->SetKeyboardFocusOnSearch();
  226. }
  227. }
  228. void FContentBrowserSingleton::CreateNewAsset(const FString& DefaultAssetName, const FString& PackagePath, UClass* AssetClass, UFactory* Factory)
  229. {
  230. FocusPrimaryContentBrowser(false);
  231. if ( PrimaryContentBrowser.IsValid() )
  232. {
  233. PrimaryContentBrowser.Pin()->CreateNewAsset(DefaultAssetName, PackagePath, AssetClass, Factory);
  234. }
  235. }
  236. TSharedPtr<SExtContentBrowser> FContentBrowserSingleton::FindContentBrowserToSync(bool bAllowLockedBrowsers, const FName& InstanceName, bool bNewSpawnBrowser)
  237. {
  238. TSharedPtr<SExtContentBrowser> ContentBrowserToSync;
  239. if (InstanceName.IsValid() && !InstanceName.IsNone())
  240. {
  241. for (int32 BrowserIdx = 0; BrowserIdx < AllContentBrowsers.Num(); ++BrowserIdx)
  242. {
  243. if (AllContentBrowsers[BrowserIdx].IsValid() && AllContentBrowsers[BrowserIdx].Pin()->GetInstanceName() == InstanceName)
  244. {
  245. return AllContentBrowsers[BrowserIdx].Pin();
  246. }
  247. }
  248. return ContentBrowserToSync;
  249. }
  250. if ( !PrimaryContentBrowser.IsValid() )
  251. {
  252. ChooseNewPrimaryBrowser();
  253. }
  254. if ( PrimaryContentBrowser.IsValid() && (bAllowLockedBrowsers || !PrimaryContentBrowser.Pin()->IsLocked()) )
  255. {
  256. // If wanting to spawn a new browser window, don't set the BrowserToSync in order to summon a new browser
  257. if (!bNewSpawnBrowser)
  258. {
  259. // If the primary content browser is not locked, sync it
  260. ContentBrowserToSync = PrimaryContentBrowser.Pin();
  261. }
  262. }
  263. else
  264. {
  265. // If there is no primary or it is locked, find the first non-locked valid browser
  266. for (int32 BrowserIdx = 0; BrowserIdx < AllContentBrowsers.Num(); ++BrowserIdx)
  267. {
  268. if ( AllContentBrowsers[BrowserIdx].IsValid() && (bAllowLockedBrowsers || !AllContentBrowsers[BrowserIdx].Pin()->IsLocked()) )
  269. {
  270. ContentBrowserToSync = AllContentBrowsers[BrowserIdx].Pin();
  271. break;
  272. }
  273. }
  274. }
  275. if ( !ContentBrowserToSync.IsValid() )
  276. {
  277. // There are no valid, unlocked browsers, attempt to summon a new one.
  278. const FName NewBrowserName = SummonNewBrowser(bAllowLockedBrowsers);
  279. // Now try to find a non-locked valid browser again, now that a new one may exist
  280. for (int32 BrowserIdx = 0; BrowserIdx < AllContentBrowsers.Num(); ++BrowserIdx)
  281. {
  282. if ((AllContentBrowsers[BrowserIdx].IsValid() && (NewBrowserName == NAME_None && (bAllowLockedBrowsers || !AllContentBrowsers[BrowserIdx].Pin()->IsLocked()))) || (AllContentBrowsers[BrowserIdx].Pin()->GetInstanceName() == NewBrowserName))
  283. {
  284. ContentBrowserToSync = AllContentBrowsers[BrowserIdx].Pin();
  285. break;
  286. }
  287. }
  288. }
  289. if ( !ContentBrowserToSync.IsValid() )
  290. {
  291. UE_LOG( LogContentBrowser, Log, TEXT( "Unable to sync content browser, all browsers appear to be locked" ) );
  292. }
  293. return ContentBrowserToSync;
  294. }
  295. void FContentBrowserSingleton::SyncBrowserToAssets(const TArray<FAssetData>& AssetDataList, bool bAllowLockedBrowsers, bool bFocuSExtContentBrowser, const FName& InstanceName, bool bNewSpawnBrowser)
  296. {
  297. TSharedPtr<SExtContentBrowser> ContentBrowserToSync = FindContentBrowserToSync(bAllowLockedBrowsers, InstanceName, bNewSpawnBrowser);
  298. if ( ContentBrowserToSync.IsValid() )
  299. {
  300. // Finally, focus and sync the browser that was found
  301. if (bFocuSExtContentBrowser)
  302. {
  303. FocuSExtContentBrowser(ContentBrowserToSync);
  304. }
  305. ContentBrowserToSync->SyncToAssets(AssetDataList);
  306. }
  307. }
  308. void FContentBrowserSingleton::SyncBrowserToAssets(const TArray<UObject*>& AssetList, bool bAllowLockedBrowsers, bool bFocuSExtContentBrowser, const FName& InstanceName, bool bNewSpawnBrowser)
  309. {
  310. // Convert UObject* array to FAssetData array
  311. TArray<FAssetData> AssetDataList;
  312. for (int32 AssetIdx = 0; AssetIdx < AssetList.Num(); ++AssetIdx)
  313. {
  314. if ( AssetList[AssetIdx] )
  315. {
  316. AssetDataList.Add( FAssetData(AssetList[AssetIdx]) );
  317. }
  318. }
  319. SyncBrowserToAssets(AssetDataList, bAllowLockedBrowsers, bFocuSExtContentBrowser, InstanceName, bNewSpawnBrowser);
  320. }
  321. void FContentBrowserSingleton::SyncBrowserToFolders(const TArray<FString>& FolderList, bool bAllowLockedBrowsers, bool bFocuSExtContentBrowser, const FName& InstanceName, bool bNewSpawnBrowser)
  322. {
  323. TSharedPtr<SExtContentBrowser> ContentBrowserToSync = FindContentBrowserToSync(bAllowLockedBrowsers, InstanceName, bNewSpawnBrowser);
  324. if ( ContentBrowserToSync.IsValid() )
  325. {
  326. // Finally, focus and sync the browser that was found
  327. if (bFocuSExtContentBrowser)
  328. {
  329. FocuSExtContentBrowser(ContentBrowserToSync);
  330. }
  331. ContentBrowserToSync->SyncToFolders(FolderList);
  332. }
  333. }
  334. void FContentBrowserSingleton::SyncBrowserTo(const FExtContentBrowserSelection& ItemSelection, bool bAllowLockedBrowsers, bool bFocuSExtContentBrowser, const FName& InstanceName, bool bNewSpawnBrowser)
  335. {
  336. TSharedPtr<SExtContentBrowser> ContentBrowserToSync = FindContentBrowserToSync(bAllowLockedBrowsers, InstanceName, bNewSpawnBrowser);
  337. if ( ContentBrowserToSync.IsValid() )
  338. {
  339. // Finally, focus and sync the browser that was found
  340. if (bFocuSExtContentBrowser)
  341. {
  342. FocuSExtContentBrowser(ContentBrowserToSync);
  343. }
  344. ContentBrowserToSync->SyncTo(ItemSelection);
  345. }
  346. }
  347. #endif
  348. void FExtContentBrowserSingleton::GetSelectedAssets(TArray<FExtAssetData>& SelectedAssets)
  349. {
  350. if ( PrimaryContentBrowser.IsValid() )
  351. {
  352. PrimaryContentBrowser.Pin()->GetSelectedAssets(SelectedAssets);
  353. }
  354. }
  355. #if ECB_LEGACY
  356. void FContentBrowserSingleton::GetSelectedFolders(TArray<FString>& SelectedFolders)
  357. {
  358. if (PrimaryContentBrowser.IsValid())
  359. {
  360. PrimaryContentBrowser.Pin()->GetSelectedFolders(SelectedFolders);
  361. }
  362. }
  363. void FContentBrowserSingleton::GetSelectedPathViewFolders(TArray<FString>& SelectedFolders)
  364. {
  365. if (PrimaryContentBrowser.IsValid())
  366. {
  367. SelectedFolders = PrimaryContentBrowser.Pin()->GetSelectedPathViewFolders();
  368. }
  369. }
  370. void FContentBrowserSingleton::CaptureThumbnailFromViewport(FViewport* InViewport, TArray<FAssetData>& SelectedAssets)
  371. {
  372. ContentBrowserUtils::CaptureThumbnailFromViewport(InViewport, SelectedAssets);
  373. }
  374. #endif
  375. FExtContentBrowserSingleton& FExtContentBrowserSingleton::Get()
  376. {
  377. static const FName ModuleName = "ExtContentBrowser";
  378. FExtContentBrowserModule& Module = FModuleManager::GetModuleChecked<FExtContentBrowserModule>(ModuleName);
  379. return static_cast<FExtContentBrowserSingleton&>(Module.Get());
  380. }
  381. FExtAssetRegistry& FExtContentBrowserSingleton::GetAssetRegistry()
  382. {
  383. return ExtAssetRegistry;
  384. }
  385. FExtObjectThumbnailPool& FExtContentBrowserSingleton::GetThumbnailPool()
  386. {
  387. return Get().ThumbnailPool;
  388. }
  389. FString FExtContentBrowserSingleton::GetPluginResourcesDir()
  390. {
  391. return Get().PluginInfo.ResourcesDir;
  392. }
  393. FText FExtContentBrowserSingleton::GetPluginVersionText()
  394. {
  395. return Get().PluginInfo.VersionName;
  396. }
  397. void FExtContentBrowserSingleton::SetPrimaryContentBrowser(const TSharedRef<SExtContentBrowser>& NewPrimaryBrowser)
  398. {
  399. if ( PrimaryContentBrowser.IsValid() && PrimaryContentBrowser.Pin().ToSharedRef() == NewPrimaryBrowser )
  400. {
  401. // This is already the primary content browser
  402. return;
  403. }
  404. if ( PrimaryContentBrowser.IsValid() )
  405. {
  406. PrimaryContentBrowser.Pin()->SetIsPrimaryContentBrowser(false);
  407. }
  408. PrimaryContentBrowser = NewPrimaryBrowser;
  409. NewPrimaryBrowser->SetIsPrimaryContentBrowser(true);
  410. }
  411. #if ECB_WIP_MULTI_INSTANCES
  412. void FContentBrowserSingleton::ContentBrowserClosed(const TSharedRef<SExtContentBrowser>& ClosedBrowser)
  413. {
  414. // Find the browser in the all browsers list
  415. for (int32 BrowserIdx = AllContentBrowsers.Num() - 1; BrowserIdx >= 0; --BrowserIdx)
  416. {
  417. if ( !AllContentBrowsers[BrowserIdx].IsValid() || AllContentBrowsers[BrowserIdx].Pin() == ClosedBrowser )
  418. {
  419. AllContentBrowsers.RemoveAt(BrowserIdx);
  420. }
  421. }
  422. if ( !PrimaryContentBrowser.IsValid() || ClosedBrowser == PrimaryContentBrowser.Pin() )
  423. {
  424. ChooseNewPrimaryBrowser();
  425. }
  426. BrowserToLastKnownTabManagerMap.Add(ClosedBrowser->GetInstanceName(), ClosedBrowser->GetTabManager());
  427. }
  428. void FContentBrowserSingleton::SharedCreateAssetDialogWindow(const TSharedRef<SAssetDialog>& AssetDialog, const FSharedAssetDialogConfig& InConfig, bool bModal) const
  429. {
  430. const FVector2D DefaultWindowSize(1152.0f, 648.0f);
  431. const FVector2D WindowSize = InConfig.WindowSizeOverride.IsZero() ? DefaultWindowSize : InConfig.WindowSizeOverride;
  432. const FText WindowTitle = InConfig.DialogTitleOverride.IsEmpty() ? LOCTEXT("GenericAssetDialogWindowHeader", "Asset Dialog") : InConfig.DialogTitleOverride;
  433. TSharedRef<SWindow> DialogWindow =
  434. SNew(SWindow)
  435. .Title(WindowTitle)
  436. .ClientSize(WindowSize);
  437. DialogWindow->SetContent(AssetDialog);
  438. IMainFrameModule& MainFrameModule = FModuleManager::LoadModuleChecked<IMainFrameModule>(TEXT("MainFrame"));
  439. const TSharedPtr<SWindow>& MainFrameParentWindow = MainFrameModule.GetParentWindow();
  440. if (MainFrameParentWindow.IsValid())
  441. {
  442. if (bModal)
  443. {
  444. FSlateApplication::Get().AddModalWindow(DialogWindow, MainFrameParentWindow.ToSharedRef());
  445. }
  446. else if (FGlobalTabmanager::Get()->GetRootWindow().IsValid())
  447. {
  448. FSlateApplication::Get().AddWindowAsNativeChild(DialogWindow, MainFrameParentWindow.ToSharedRef());
  449. }
  450. else
  451. {
  452. FSlateApplication::Get().AddWindow(DialogWindow);
  453. }
  454. }
  455. else
  456. {
  457. if (ensureMsgf(!bModal, TEXT("Could not create asset dialog because modal windows must have a parent and this was called at a time where the mainframe window does not exist.")))
  458. {
  459. FSlateApplication::Get().AddWindow(DialogWindow);
  460. }
  461. }
  462. }
  463. #if ECB_WIP_MULTI_INSTANCES
  464. void FContentBrowserSingleton::ChooseNewPrimaryBrowser()
  465. {
  466. // Find the first valid browser and trim any invalid browsers along the way
  467. for (int32 BrowserIdx = 0; BrowserIdx < AllContentBrowsers.Num(); ++BrowserIdx)
  468. {
  469. if ( AllContentBrowsers[BrowserIdx].IsValid() )
  470. {
  471. if (AllContentBrowsers[BrowserIdx].Pin()->CanSetAsPrimaryContentBrowser())
  472. {
  473. SetPrimaryContentBrowser(AllContentBrowsers[BrowserIdx].Pin().ToSharedRef());
  474. break;
  475. }
  476. }
  477. else
  478. {
  479. // Trim any invalid content browsers
  480. AllContentBrowsers.RemoveAt(BrowserIdx);
  481. BrowserIdx--;
  482. }
  483. }
  484. }
  485. #endif
  486. void FContentBrowserSingleton::FocuSExtContentBrowser(const TSharedPtr<SExtContentBrowser>& BrowserToFocus)
  487. {
  488. if ( BrowserToFocus.IsValid() )
  489. {
  490. TSharedRef<SExtContentBrowser> Browser = BrowserToFocus.ToSharedRef();
  491. TSharedPtr<FTabManager> TabManager = Browser->GetTabManager();
  492. if ( TabManager.IsValid() )
  493. {
  494. TabManager->InvokeTab(Browser->GetInstanceName());
  495. }
  496. }
  497. }
  498. FName FContentBrowserSingleton::SummonNewBrowser(bool bAllowLockedBrowsers)
  499. {
  500. TSet<FName> OpenBrowserIDs;
  501. // Find all currently open browsers to help find the first open slot
  502. for (int32 BrowserIdx = AllContentBrowsers.Num() - 1; BrowserIdx >= 0; --BrowserIdx)
  503. {
  504. const TWeakPtr<SExtContentBrowser>& Browser = AllContentBrowsers[BrowserIdx];
  505. if ( Browser.IsValid() )
  506. {
  507. OpenBrowserIDs.Add(Browser.Pin()->GetInstanceName());
  508. }
  509. }
  510. FName NewTabName;
  511. for ( int32 BrowserIdx = 0; BrowserIdx < UE_ARRAY_COUNT(ContentBrowserTabIDs); BrowserIdx++ )
  512. {
  513. FName TestTabID = ContentBrowserTabIDs[BrowserIdx];
  514. if ( !OpenBrowserIDs.Contains(TestTabID) && (bAllowLockedBrowsers || !IsLocked(TestTabID)) )
  515. {
  516. // Found the first index that is not currently open
  517. NewTabName = TestTabID;
  518. break;
  519. }
  520. }
  521. if ( NewTabName != NAME_None )
  522. {
  523. const TWeakPtr<FTabManager>& TabManagerToInvoke = BrowserToLastKnownTabManagerMap.FindRef(NewTabName);
  524. if ( TabManagerToInvoke.IsValid() )
  525. {
  526. TabManagerToInvoke.Pin()->InvokeTab(NewTabName);
  527. }
  528. else
  529. {
  530. FGlobalTabmanager::Get()->InvokeTab(NewTabName);
  531. }
  532. }
  533. else
  534. {
  535. // No available slots... don't summon anything
  536. }
  537. return NewTabName;
  538. }
  539. #endif
  540. TSharedRef<SWidget> FExtContentBrowserSingleton::CreateContentBrowser( const FName InstanceName, TSharedPtr<SDockTab> ContainingTab)
  541. {
  542. TSharedRef<SExtContentBrowser> NewBrowser =
  543. SNew(SExtContentBrowser, InstanceName)
  544. .IsEnabled( FSlateApplication::Get().GetNormalExecutionAttribute() )
  545. .ContainingTab( ContainingTab );
  546. #if ECB_WIP_MULTI_INSTANCES
  547. AllContentBrowsers.Add( NewBrowser );
  548. if( !PrimaryContentBrowser.IsValid() )
  549. {
  550. ChooseNewPrimaryBrowser();
  551. }
  552. #else
  553. SetPrimaryContentBrowser(NewBrowser);
  554. #endif
  555. return NewBrowser;
  556. }
  557. void FExtContentBrowserSingleton::RegisterEditorDelegates()
  558. {
  559. FEditorDelegates::BeginPIE.AddRaw(this, &FExtContentBrowserSingleton::OnBeginPIE);
  560. FEditorDelegates::EndPIE.AddRaw(this, &FExtContentBrowserSingleton::OnEndPIE);
  561. }
  562. void FExtContentBrowserSingleton::UnregisterEditorDelegates()
  563. {
  564. FEditorDelegates::BeginPIE.RemoveAll(this);
  565. FEditorDelegates::EndPIE.RemoveAll(this);
  566. }
  567. // Todo: alert sandbox usage
  568. void FExtContentBrowserSingleton::OnBeginPIE(const bool bIsSimulating)
  569. {
  570. }
  571. void FExtContentBrowserSingleton::OnEndPIE(const bool bIsSimulating)
  572. {
  573. }
  574. void FExtContentBrowserSingleton::MountSandbox()
  575. {
  576. #if ECB_WIP_IMPORT_SANDBOX
  577. FPackageName::RegisterMountPoint(FExtAssetData::GetSandboxPackagePath() + TEXT("/"), FExtAssetData::GetSandboxDir());
  578. #endif
  579. }
  580. void FExtContentBrowserSingleton::UnMountSandbox()
  581. {
  582. #if ECB_WIP_IMPORT_SANDBOX
  583. FPackageName::UnRegisterMountPoint(FExtAssetData::GetSandboxPackagePath() + TEXT("/"), FExtAssetData::GetSandboxDir());
  584. #endif
  585. }
  586. void FExtContentBrowserSingleton::RegisterMenuAndTabSpawner()
  587. {
  588. struct MenuGroupHelper
  589. {
  590. static TSharedRef<FWorkspaceItem> FindOrCreateGroup(const FText& InGroupName)
  591. {
  592. TSharedRef<FWorkspaceItem> MenuRoot = WorkspaceMenu::GetMenuStructure().GetStructureRoot();
  593. const TArray<TSharedRef<FWorkspaceItem>>& ChildItems = MenuRoot->GetChildItems();
  594. for (const TSharedRef<FWorkspaceItem>& ChildItem : ChildItems)
  595. {
  596. if (ChildItem->GetDisplayName().EqualTo(InGroupName))
  597. {
  598. return ChildItem;
  599. }
  600. }
  601. return MenuRoot->AddGroup(InGroupName);;
  602. }
  603. };
  604. // Register the tab spawner for all content browsers
  605. const FText NatesToolGroupName = LOCTEXT("NatesTools", "Nate's Tools");
  606. TSharedRef<FWorkspaceItem> NatesToolsMenuGroup = MenuGroupHelper::FindOrCreateGroup(NatesToolGroupName);
  607. //const FSlateIcon AssetBrowserIcon(FAppStyle::GetStyleSetName(), "ContentBrowser.TabIcon");
  608. const FSlateIcon AssetBrowserIcon(FExtContentBrowserStyle::GetStyleSetName(), "UAssetBrowser.Icon16x");
  609. for (int32 BrowserIdx = 0; BrowserIdx < UE_ARRAY_COUNT(ContentBrowserTabIDs); BrowserIdx++)
  610. {
  611. const FName TabID = FName(*FString::Printf(TEXT("UAssetBrowserTab%d"), BrowserIdx + 1));
  612. ContentBrowserTabIDs[BrowserIdx] = TabID;
  613. const FText DefaultDisplayName = GetContentBrowserLabelWithIndex(BrowserIdx);
  614. FGlobalTabmanager::Get()->RegisterNomadTabSpawner(TabID, FOnSpawnTab::CreateRaw(this, &FExtContentBrowserSingleton::SpawnContentBrowserTab, BrowserIdx))
  615. #if ECB_WIP_MULTI_INSTANCES
  616. .SetDisplayName(DefaultDisplayName)
  617. #else
  618. .SetDisplayName(LOCTEXT("UAssetBrowserTabTitle", "UAsset Browser"))
  619. #endif
  620. .SetTooltipText(LOCTEXT("UAssetBrowserMenuTooltipText", "Open a UAsset Browser tab."))
  621. .SetIcon(AssetBrowserIcon)
  622. .SetGroup(NatesToolsMenuGroup)
  623. .SetMenuType(ETabSpawnerMenuType::Enabled);
  624. }
  625. }
  626. void FExtContentBrowserSingleton::RegisterCommands()
  627. {
  628. FExtContentBrowserCommands::Register();
  629. ExtContentBrowserCommands = MakeShareable(new FUICommandList);
  630. ExtContentBrowserCommands->MapAction(FExtContentBrowserCommands::Get().OpenUAssetBrowser, FExecuteAction::CreateRaw(this, &FExtContentBrowserSingleton::OpenUAssetBrowserButtonClicked), FCanExecuteAction());
  631. }
  632. void FExtContentBrowserSingleton::AddToolbarExtension(FToolBarBuilder& Builder)
  633. {
  634. Builder.AddToolBarButton(FExtContentBrowserCommands::Get().OpenUAssetBrowser);
  635. }
  636. void FExtContentBrowserSingleton::OpenUAssetBrowserButtonClicked() const
  637. {
  638. const FName ExtContentBrowserTabName("UAssetBrowserTab1");
  639. //FGlobalTabmanager::Get()->InvokeTab(ExtContentBrowserTabName);
  640. FLevelEditorModule& LevelEditorModule = FModuleManager::GetModuleChecked<FLevelEditorModule>(TEXT("LevelEditor"));
  641. LevelEditorModule.GetLevelEditorTabManager()->TryInvokeTab(ExtContentBrowserTabName);
  642. }
  643. TSharedRef<SDockTab> FExtContentBrowserSingleton::SpawnContentBrowserTab( const FSpawnTabArgs& SpawnTabArgs, int32 BrowserIdx )
  644. {
  645. TAttribute<FText> Label = TAttribute<FText>::Create( TAttribute<FText>::FGetter::CreateRaw( this, &FExtContentBrowserSingleton::GetContentBrowserTabLabel, BrowserIdx ) );
  646. TSharedRef<SDockTab> NewTab = SNew(SDockTab)
  647. .TabRole(ETabRole::NomadTab)
  648. .Label(Label);
  649. //.ToolTip( IDocumentation::Get()->CreateToolTip( Label, nullptr, "Shared/ContentBrowser", "Tab" ) );
  650. TSharedRef<SWidget> NewBrowser = CreateContentBrowser( SpawnTabArgs.GetTabId().TabType, NewTab);
  651. #if ECB_WIP_MULTI_INSTANCES
  652. if ( !PrimaryContentBrowser.IsValid() )
  653. {
  654. ChooseNewPrimaryBrowser();
  655. }
  656. #endif
  657. #if ECB_LEGACY
  658. // Add wrapper for tutorial highlighting
  659. TSharedRef<SBox> Wrapper =
  660. SNew(SBox)
  661. .AddMetaData<FTutorialMetaData>(FTutorialMetaData(TEXT("ContentBrowser"), TEXT("ContentBrowserTab1")))
  662. [
  663. NewBrowser
  664. ];
  665. NewTab->SetContent( Wrapper );
  666. #endif
  667. NewTab->SetContent(NewBrowser);
  668. return NewTab;
  669. }
  670. #if ECB_WIP_LOCK
  671. bool FContentBrowserSingleton::IsLocked(const FName& InstanceName) const
  672. {
  673. // First try all the open browsers, as their locked state might be newer than the configs
  674. for (int32 AllBrowsersIdx = AllContentBrowsers.Num() - 1; AllBrowsersIdx >= 0; --AllBrowsersIdx)
  675. {
  676. const TWeakPtr<SExtContentBrowser>& Browser = AllContentBrowsers[AllBrowsersIdx];
  677. if ( Browser.IsValid() && Browser.Pin()->GetInstanceName() == InstanceName )
  678. {
  679. return Browser.Pin()->IsLocked();
  680. }
  681. }
  682. // Fallback to getting the locked state from the config instead
  683. bool bIsLocked = false;
  684. GConfig->GetBool(*SExtContentBrowser::SettingsIniSection, *(InstanceName.ToString() + TEXT(".Locked")), bIsLocked, GEditorPerProjectIni);
  685. return bIsLocked;
  686. }
  687. #endif
  688. FText FExtContentBrowserSingleton::GetContentBrowserLabelWithIndex( int32 BrowserIdx )
  689. {
  690. return FText::Format(LOCTEXT("UAssetBrowserTabNameWithIndex", "UAsset Browser {0}"), FText::AsNumber(BrowserIdx + 1));
  691. }
  692. void FExtContentBrowserSingleton::ToggleShowToolbarButton()
  693. {
  694. const bool bShowToolbarButton = !GetDefault<UExtContentBrowserSettings>()->DisplayToolbarButton;
  695. GetMutableDefault<UExtContentBrowserSettings>()->DisplayToolbarButton = bShowToolbarButton;
  696. if (bShowToolbarButton)
  697. {
  698. if (!ToolbarExtension.IsValid())
  699. {
  700. // ToolbarExtender = MakeShareable(new FExtender);
  701. ToolbarExtension = ToolbarExtender->AddToolBarExtension("Settings", EExtensionHook::After, ExtContentBrowserCommands, FToolBarExtensionDelegate::CreateRaw(this, &FExtContentBrowserSingleton::AddToolbarExtension));
  702. // FLevelEditorModule& LevelEditorModule = FModuleManager::LoadModuleChecked<FLevelEditorModule>("LevelEditor");
  703. // LevelEditorModule.GetToolBarExtensibilityManager()->AddExtender(ToolbarExtender);
  704. }
  705. }
  706. else
  707. {
  708. if (ToolbarExtension.IsValid())
  709. {
  710. ToolbarExtender->RemoveExtension(ToolbarExtension.ToSharedRef());
  711. // FLevelEditorModule& LevelEditorModule = FModuleManager::LoadModuleChecked<FLevelEditorModule>("LevelEditor");
  712. // LevelEditorModule.GetToolBarExtensibilityManager()->RemoveExtender(ToolbarExtender);
  713. }
  714. ToolbarExtension = nullptr;
  715. // ToolbarExtender = nullptr;
  716. }
  717. }
  718. FText FExtContentBrowserSingleton::GetContentBrowserTabLabel(int32 BrowserIdx)
  719. {
  720. #if ECB_WIP_MULTI_INSTANCES
  721. int32 NumOpenContentBrowsers = 0;
  722. for (int32 AllBrowsersIdx = AllContentBrowsers.Num() - 1; AllBrowsersIdx >= 0; --AllBrowsersIdx)
  723. {
  724. const TWeakPtr<SExtContentBrowser>& Browser = AllContentBrowsers[AllBrowsersIdx];
  725. if ( Browser.IsValid() )
  726. {
  727. NumOpenContentBrowsers++;
  728. }
  729. else
  730. {
  731. AllContentBrowsers.RemoveAt(AllBrowsersIdx);
  732. }
  733. }
  734. if ( NumOpenContentBrowsers > 1 )
  735. {
  736. return GetContentBrowserLabelWithIndex( BrowserIdx );
  737. }
  738. else
  739. #endif
  740. {
  741. return LOCTEXT("UAssetBrowserTabName", "UAsset Browser");
  742. }
  743. }
  744. #if ECB_WIP_MULTI_INSTANCES
  745. void FContentBrowserSingleton::SetSelectedPaths(const TArray<FString>& FolderPaths, bool bNeedsRefresh/* = false*/)
  746. {
  747. // Make sure we have a valid browser
  748. if (!PrimaryContentBrowser.IsValid())
  749. {
  750. ChooseNewPrimaryBrowser();
  751. if (!PrimaryContentBrowser.IsValid())
  752. {
  753. SummonNewBrowser();
  754. }
  755. }
  756. if (PrimaryContentBrowser.IsValid())
  757. {
  758. PrimaryContentBrowser.Pin()->SetSelectedPaths(FolderPaths, bNeedsRefresh);
  759. }
  760. }
  761. #endif
  762. /////////////////////////////////////
  763. // FPluginfo Impl
  764. //
  765. FExtContentBrowserPluginInfo::FExtContentBrowserPluginInfo()
  766. {
  767. TSharedPtr<IPlugin> MyPlugin = IPluginManager::Get().FindPlugin(TEXT("UAssetBrowser"));
  768. FriendlyName = FText::FromString(MyPlugin->GetDescriptor().FriendlyName);
  769. VersionName = FText::FromString(TEXT("v") + MyPlugin->GetDescriptor().VersionName);
  770. CreatedBy = FText::FromString(TEXT("by ") + MyPlugin->GetDescriptor().CreatedBy);
  771. ResourcesDir = MyPlugin->GetBaseDir() / TEXT("Resources");
  772. }
  773. #undef LOCTEXT_NAMESPACE