|
1 | 1 | // Copyright 1998-2018 Epic Games, Inc. All Rights Reserved.
|
2 | 2 |
|
3 | 3 | #include "LinterContentBrowserExtensions.h"
|
4 |
| -#include "Modules/ModuleManager.h" |
5 |
| -#include "Framework/MultiBox/MultiBoxBuilder.h" |
6 | 4 | #include "LinterStyle.h"
|
7 | 5 | #include "ContentBrowserModule.h"
|
8 | 6 | #include "Linter.h"
|
9 | 7 | #include "BatchRenameTool/BatchRenameTool.h"
|
10 |
| -#include "Framework/MultiBox/MultiBoxExtender.h" |
11 |
| -#include "Framework/Commands/UIAction.h" |
12 |
| -#include "Delegates/IDelegateInstance.h" |
13 | 8 | #include "TooltipEditor/TooltipTool.h"
|
14 | 9 | #include "Misc/EngineVersionComparison.h"
|
15 | 10 |
|
| 11 | + |
16 | 12 | #define LOCTEXT_NAMESPACE "Linter"
|
17 | 13 |
|
18 | 14 | DEFINE_LOG_CATEGORY_STATIC(LinterContentBrowserExtensions, Log, All);
|
19 | 15 |
|
20 |
| -void FLinterContentBrowserExtensions::InstallHooks(FLinterModule* LinterModule, FDelegateHandle* pContentBrowserExtenderDelegateHandle, class FDelegateHandle* pAssetExtenderDelegateHandle) { |
21 |
| - struct Local { |
22 |
| - // Path extensions |
23 |
| - |
24 |
| - static TSharedRef<FExtender> OnExtendContentBrowserAssetSelectionMenu(const TArray<FString>& SelectedPaths) { |
25 |
| - TSharedRef<FExtender> Extender = MakeShared<FExtender>(); |
26 |
| - Extender->AddMenuExtension( |
27 |
| - "PathContextSourceControl", |
28 |
| - EExtensionHook::After, |
29 |
| - TSharedPtr<FUICommandList>(), |
30 |
| - FMenuExtensionDelegate::CreateStatic(&Local::ContentBrowserExtenderFunc, SelectedPaths) |
31 |
| - ); |
32 |
| - return Extender; |
33 |
| - } |
34 | 16 |
|
35 |
| - static void ContentBrowserExtenderFunc(FMenuBuilder& MenuBuilder, const TArray<FString> SelectedPaths) { |
36 |
| - MenuBuilder.BeginSection("LinterContentBrowserContext", LOCTEXT("CB_LinterHeader", "Linter")); |
37 |
| - { |
38 |
| - MenuBuilder.AddMenuEntry( |
39 |
| - LOCTEXT("CB_ScanProjectWithLinter", "Scan with Linter"), |
40 |
| - LOCTEXT("CB_ScanProjectWithLinter_Tooltip", "Scan project content with Linter"), |
41 |
| - FSlateIcon(FLinterStyle::GetStyleSetName(), "Linter.Toolbar.Icon"), |
42 |
| - FUIAction(FExecuteAction::CreateLambda([SelectedPaths]() { |
43 |
| - if (FLinterModule* Linter = FModuleManager::GetModulePtr<FLinterModule>("Linter")) { |
44 |
| - if (Linter != nullptr) { |
45 |
| - Linter->SetDesiredLintPaths(SelectedPaths); |
46 |
| - } |
47 |
| -#if UE_VERSION_NEWER_THAN(4, 26, 0) |
48 |
| - FGlobalTabmanager::Get()->TryInvokeTab(FName("LinterTab")); |
49 |
| -#else |
50 |
| - FGlobalTabmanager::Get()->InvokeTab(FName("LinterTab")); |
51 |
| -#endif |
52 |
| - } |
53 |
| - })), |
54 |
| - NAME_None, |
55 |
| - EUserInterfaceActionType::Button); |
56 |
| - } |
57 |
| - MenuBuilder.EndSection(); |
58 |
| - } |
| 17 | +namespace { |
59 | 18 |
|
60 |
| - // Asset extensions |
61 |
| - |
62 |
| - static TSharedRef<FExtender> OnExtendAssetSelectionMenu(const TArray<FAssetData>& SelectedAssets) { |
63 |
| - TSharedRef<FExtender> Extender = MakeShared<FExtender>(); |
64 |
| - Extender->AddMenuExtension( |
65 |
| - "CommonAssetActions", |
66 |
| - EExtensionHook::After, |
67 |
| - nullptr, |
68 |
| - FMenuExtensionDelegate::CreateStatic(&Local::AssetExtenderFunc, SelectedAssets) |
69 |
| - ); |
70 |
| - return Extender; |
71 |
| - } |
| 19 | +void RunLinterForAssets(const TArray<FString>& SelectedPaths) { |
| 20 | + // Set Paths to Linter |
| 21 | + if (FLinterModule* Linter = FModuleManager::GetModulePtr<FLinterModule>("Linter")) { |
| 22 | + Linter->SetDesiredLintPaths(SelectedPaths); |
| 23 | + } |
72 | 24 |
|
73 |
| - static void AssetExtenderFunc(FMenuBuilder& MenuBuilder, const TArray<FAssetData> SelectedAssets) { |
74 |
| - MenuBuilder.BeginSection("LinterAssetContext", LOCTEXT("CB_LinterHeader", "Linter")); |
75 |
| - { |
76 |
| - // Run through the assets to determine if any are blueprints |
77 |
| - bool bAnyBlueprintsSelected = false; |
78 |
| - for (auto AssetIt = SelectedAssets.CreateConstIterator(); AssetIt; ++AssetIt) { |
79 |
| - const FAssetData& Asset = *AssetIt; |
80 |
| - // Cannot rename redirectors or classes or cooked packages |
81 |
| -#if UE_VERSION_NEWER_THAN(5, 1, 0) |
82 |
| - if (!Asset.IsRedirector() && Asset.AssetClassPath.GetAssetName() != NAME_Class && !(Asset.PackageFlags & PKG_FilterEditorOnly)) |
| 25 | + // Execute Linter |
| 26 | +#if UE_VERSION_NEWER_THAN(4, 26, 0) |
| 27 | + FGlobalTabmanager::Get()->TryInvokeTab(FName("LinterTab")); |
83 | 28 | #else
|
84 |
| - if (!Asset.IsRedirector() && Asset.AssetClass != NAME_Class && !(Asset.PackageFlags & PKG_FilterEditorOnly)) |
| 29 | + FGlobalTabmanager::Get()->InvokeTab(FName("LinterTab")); |
85 | 30 | #endif
|
86 |
| - { |
87 |
| - if (Asset.GetClass()->IsChildOf(UBlueprint::StaticClass())) { |
88 |
| - bAnyBlueprintsSelected = true; |
89 |
| - break; |
90 |
| - } |
91 |
| - } |
92 |
| - } |
| 31 | +} |
93 | 32 |
|
94 |
| - // If we have blueprints selected, enable blueprint tools |
95 |
| - if (bAnyBlueprintsSelected) { |
96 |
| - // Add Tooltip Editor |
97 |
| - MenuBuilder.AddMenuEntry( |
98 |
| - LOCTEXT("CB_EditBlueprintTooltips", "Edit Blueprint Tooltips (Experimental)"), |
99 |
| - LOCTEXT("CB_EditBlueprintTooltips_Tooltip", "Edit selected blueprints' templates definitions"), |
100 |
| - FSlateIcon(FLinterStyle::GetStyleSetName(), "Linter.Toolbar.Icon"), |
101 |
| - FUIAction(FExecuteAction::CreateLambda([SelectedAssets]() { |
102 |
| - UE_LOG(LinterContentBrowserExtensions, Display, TEXT("Opening Tooltip Tool window.")); |
103 |
| - FTooltipTool AssetDlg(SelectedAssets); |
104 |
| - if (AssetDlg.ShowModal() == FTooltipTool::Confirm) { |
105 |
| - UE_LOG(LinterContentBrowserExtensions, Display, TEXT("Tooltip Tool did the thing.")); |
106 |
| - } |
107 |
| - })), |
108 |
| - NAME_None, |
109 |
| - EUserInterfaceActionType::Button); |
110 |
| - } |
| 33 | +void EditBlueprintTooltips(const TArray<FAssetData> SelectedAssets) { |
| 34 | + UE_LOG(LinterContentBrowserExtensions, Display, TEXT("Opening Tooltip Tool window.")); |
| 35 | + FTooltipTool{SelectedAssets}.ShowModal(); |
| 36 | +} |
| 37 | + |
| 38 | +void BatchRenameAssets(const TArray<FAssetData> SelectedAssets) { |
| 39 | + UE_LOG(LinterContentBrowserExtensions, Display, TEXT("Starting batch rename.")); |
| 40 | + FDlgBatchRenameTool{SelectedAssets}.ShowModal(); |
| 41 | +} |
111 | 42 |
|
112 |
| - // Run through the assets to see if any can be renamed |
113 |
| - bool bAnyAssetCanBeRenamed = false; |
114 |
| - for (auto AssetIt = SelectedAssets.CreateConstIterator(); AssetIt; ++AssetIt) { |
115 |
| - const FAssetData& Asset = *AssetIt; |
116 |
| - // Cannot rename redirectors or classes or cooked packages |
| 43 | +// Asset Context Menu is dynamic -> some options will only be displayed if |
| 44 | +// you have certain types of Blueprints or Assets selected |
| 45 | +void CreateDynamicAssetSelectionMenu(UToolMenu* InMenu) { |
| 46 | + const auto* Context = InMenu->FindContext<UContentBrowserDataMenuContext_FileMenu>(); |
| 47 | + FToolMenuSection& Section = InMenu->AddSection("Linter", LOCTEXT("LinterSection", "Linter")); |
| 48 | + |
| 49 | + // Convert BrowserItems to their AssetData |
| 50 | + TArray<FAssetData> Assets; |
| 51 | + for (const auto& Asset : Context->SelectedItems) { |
| 52 | + FAssetData AssetData; |
| 53 | + Asset.Legacy_TryGetAssetData(AssetData); |
| 54 | + Assets.Add(AssetData); |
| 55 | + } |
| 56 | + |
| 57 | + // Run through the assets to determine if any are blueprints or can be renamed |
| 58 | + bool bAnyBlueprintsSelected = false; |
| 59 | + bool bAnyAssetCanBeRenamed = false; |
| 60 | + |
| 61 | + for (const auto& Asset : Assets) { |
| 62 | + // Cannot rename redirectors or classes or cooked packages |
117 | 63 | #if UE_VERSION_NEWER_THAN(5, 1, 0)
|
118 |
| - if (!Asset.IsRedirector() && Asset.AssetClassPath.GetAssetName() != NAME_Class && !(Asset.PackageFlags & PKG_FilterEditorOnly)) |
| 64 | + if (!Asset.IsRedirector() && Asset.AssetClassPath.GetAssetName() != NAME_Class && !(Asset.PackageFlags & PKG_FilterEditorOnly)) |
119 | 65 | #else
|
120 |
| - if (!Asset.IsRedirector() && Asset.AssetClass != NAME_Class && !(Asset.PackageFlags & PKG_FilterEditorOnly)) |
| 66 | + if (!Asset.IsRedirector() && Asset.AssetClass != NAME_Class && !(Asset.PackageFlags & PKG_FilterEditorOnly)) |
121 | 67 | #endif
|
122 |
| - { |
123 |
| - bAnyAssetCanBeRenamed = true; |
124 |
| - break; |
125 |
| - } |
126 |
| - } |
127 |
| - |
128 |
| - if (bAnyAssetCanBeRenamed) { |
129 |
| - // Add Tooltip Editor |
130 |
| - MenuBuilder.AddMenuEntry( |
131 |
| - LOCTEXT("CB_BatchRenameAssets", "Batch Rename Assets (Experimental)"), |
132 |
| - LOCTEXT("CB_BatchRenameAssets_Tooltip", "Perform a bulk rename operation on all of the selected assets"), |
133 |
| - FSlateIcon(FLinterStyle::GetStyleSetName(), "Linter.Toolbar.Icon"), |
134 |
| - FUIAction(FExecuteAction::CreateLambda([SelectedAssets]() { |
135 |
| - UE_LOG(LinterContentBrowserExtensions, Display, TEXT("Starting batch rename.")); |
136 |
| - FDlgBatchRenameTool AssetDlg(SelectedAssets); |
137 |
| - AssetDlg.ShowModal(); |
138 |
| - })), |
139 |
| - NAME_None, |
140 |
| - EUserInterfaceActionType::Button); |
141 |
| - } |
| 68 | + { |
| 69 | + bAnyAssetCanBeRenamed = true; |
| 70 | + |
| 71 | + if (Asset.GetClass()->IsChildOf(UBlueprint::StaticClass())) { |
| 72 | + bAnyBlueprintsSelected = true; |
| 73 | + break; |
142 | 74 | }
|
143 |
| - MenuBuilder.EndSection(); |
144 | 75 | }
|
145 |
| - }; |
| 76 | + } |
| 77 | + |
| 78 | + // If we have blueprints selected, add Tooltip Editor |
| 79 | + if (bAnyBlueprintsSelected) { |
| 80 | + Section.AddMenuEntry( |
| 81 | + "EditBlueprintTooltips", |
| 82 | + LOCTEXT("EditBlueprintTooltips", "Edit Blueprint Tooltips (Experimental)"), |
| 83 | + LOCTEXT("EditBlueprintTooltips_Tooltip", "Edit selected blueprints' templates definitions"), |
| 84 | + FSlateIcon(FLinterStyle::GetStyleSetName(), "Linter.Toolbar.Icon"), |
| 85 | + FExecuteAction::CreateStatic(&EditBlueprintTooltips, Assets) |
| 86 | + ); |
| 87 | + } |
| 88 | + |
| 89 | + // If blueprints can be renamed, add the batch rename option |
| 90 | + if (bAnyAssetCanBeRenamed) { |
| 91 | + Section.AddMenuEntry( |
| 92 | + "BatchRename", |
| 93 | + LOCTEXT("BatchRenameAssets", "Batch Rename Assets (Experimental)"), |
| 94 | + LOCTEXT("BatchRenameAssets_Tooltip", "Perform a bulk rename operation on all of the selected assets"), |
| 95 | + FSlateIcon(FLinterStyle::GetStyleSetName(), "Linter.Toolbar.Icon"), |
| 96 | + FExecuteAction::CreateStatic(&BatchRenameAssets, Assets) |
| 97 | + ); |
| 98 | + } |
| 99 | +} |
| 100 | + |
| 101 | +} |
146 | 102 |
|
147 |
| - FContentBrowserModule& ContentBrowserModule = FModuleManager::LoadModuleChecked<FContentBrowserModule>(TEXT("ContentBrowser")); |
148 | 103 |
|
149 |
| - // Path view extenders |
150 |
| - TArray<FContentBrowserMenuExtender_SelectedPaths>& CBMenuPathExtenderDelegates = ContentBrowserModule.GetAllPathViewContextMenuExtenders(); |
151 |
| - CBMenuPathExtenderDelegates.Add(FContentBrowserMenuExtender_SelectedPaths::CreateStatic(&Local::OnExtendContentBrowserAssetSelectionMenu)); |
152 |
| - *pContentBrowserExtenderDelegateHandle = CBMenuPathExtenderDelegates.Last().GetHandle(); |
| 104 | +void FLinterContentBrowserExtensions::InstallHooks() { |
| 105 | + // Run Linter on Selected Folder(s) |
| 106 | + UToolMenu* ContentBrowserMenu = UToolMenus::Get()->ExtendMenu("ContentBrowser.FolderContextMenu"); |
| 107 | + ContentBrowserMenu->AddSection("Linter", LOCTEXT("LinterSection", "Linter")) |
| 108 | + .AddMenuEntry( |
| 109 | + "LintAssets", |
| 110 | + LOCTEXT("ScanWithLinter", "Scan with Linter"), |
| 111 | + LOCTEXT("ScanWithLinter_Tooltip", "Scan project content with Linter"), |
| 112 | + FSlateIcon(FLinterStyle::GetStyleSetName(), "Linter.Toolbar.Icon"), |
| 113 | + FToolMenuExecuteAction::CreateLambda([](const FToolMenuContext& InContext) { |
| 114 | + if (const UContentBrowserDataMenuContext_FolderMenu* Context = InContext.FindContext<UContentBrowserDataMenuContext_FolderMenu>()) { |
| 115 | + TArray<FString> SelectedPaths; |
| 116 | + for (const auto& Asset : Context->SelectedItems) { |
| 117 | + SelectedPaths.Add(Asset.GetVirtualPath().ToString()); |
| 118 | + } |
| 119 | + |
| 120 | + RunLinterForAssets(SelectedPaths); |
| 121 | + } |
| 122 | + }) |
| 123 | + ); |
153 | 124 |
|
154 |
| - // Asset extenders |
155 |
| - TArray<FContentBrowserMenuExtender_SelectedAssets>& CBMenuAssetExtenderDelegates = ContentBrowserModule.GetAllAssetViewContextMenuExtenders(); |
156 |
| - CBMenuAssetExtenderDelegates.Add(FContentBrowserMenuExtender_SelectedAssets::CreateStatic(&Local::OnExtendAssetSelectionMenu)); |
157 |
| - *pAssetExtenderDelegateHandle = CBMenuAssetExtenderDelegates.Last().GetHandle(); |
| 125 | + // BatchRename and TooltipEditor |
| 126 | + UToolMenu* AssetMenu = UToolMenus::Get()->ExtendMenu("ContentBrowser.AssetContextMenu"); |
| 127 | + AssetMenu->AddDynamicSection("Linter", FNewToolMenuDelegate::CreateStatic(&CreateDynamicAssetSelectionMenu), {"AssetContextExploreMenuOptions", EToolMenuInsertType::After}); |
158 | 128 | }
|
159 | 129 |
|
160 |
| -void FLinterContentBrowserExtensions::RemoveHooks(FLinterModule* LinterModule, FDelegateHandle* pContentBrowserExtenderDelegateHandle, FDelegateHandle* pAssetExtenderDelegateHandle) { |
161 |
| - if (FModuleManager::Get().IsModuleLoaded("ContentBrowser")) { |
162 |
| - FContentBrowserModule& ContentBrowserModule = FModuleManager::LoadModuleChecked<FContentBrowserModule>(TEXT("ContentBrowser")); |
163 |
| - |
164 |
| - // Path view extenders |
165 |
| - TArray<FContentBrowserMenuExtender_SelectedPaths>& CBMenuExtenderDelegates = ContentBrowserModule.GetAllAssetContextMenuExtenders(); |
166 |
| - CBMenuExtenderDelegates.RemoveAll([pContentBrowserExtenderDelegateHandle](const FContentBrowserMenuExtender_SelectedPaths& Delegate) { |
167 |
| - return Delegate.GetHandle() == *pContentBrowserExtenderDelegateHandle; |
168 |
| - }); |
169 |
| - |
170 |
| - // Asset extenders |
171 |
| - TArray<FContentBrowserMenuExtender_SelectedAssets>& CBMenuAssetExtenderDelegates = ContentBrowserModule.GetAllAssetViewContextMenuExtenders(); |
172 |
| - CBMenuAssetExtenderDelegates.RemoveAll([pAssetExtenderDelegateHandle](const FContentBrowserMenuExtender_SelectedAssets& Delegate) { |
173 |
| - return Delegate.GetHandle() == *pAssetExtenderDelegateHandle; |
174 |
| - }); |
175 |
| - } |
| 130 | +void FLinterContentBrowserExtensions::RemoveHooks() { |
| 131 | + UToolMenu* ContentBrowserMenu = UToolMenus::Get()->ExtendMenu("ContentBrowser.FolderContextMenu"); |
| 132 | + ContentBrowserMenu->RemoveSection("Linter"); |
| 133 | + |
| 134 | + UToolMenu* AssetMenu = UToolMenus::Get()->ExtendMenu("ContentBrowser.AssetContextMenu"); |
| 135 | + AssetMenu->RemoveSection("Linter"); |
176 | 136 | }
|
177 | 137 |
|
178 | 138 | #undef LOCTEXT_NAMESPACE
|
0 commit comments