ashe23/ProjectCleaner

Hide folders with no unused assets from tree view

Zeblote opened this issue · 12 comments

The tree view is working really well, but I noticed that the folder tree shows every folder in the project, rather than only ones that actually have unused assets in them. Is it possible to filter the folders and hide ones that will display "no assets"?

Actually it was intentional , so you can see list of empty folders in project.

But I think some kind of checkbox in configs can show/hide empty folders, like "Show Empty Folders" .
I will check it out.

I see. But that doesn't work in practice, does it? Like, both folders that are empty and folders that have only assets in use in them will be shown here, and there is no way to tell them apart in the unused assets tab.

For example... this folder isn't empty, but it has no unused assets, so I think it should be hidden from the panel on the left

image

Maybe empty folders could be a separate view, but I'm not convinced that is actually useful. Folders are typically not tracked by version control so deleting them doesn't really do much, and they'd be gone if you make a fresh workspace anyway.

Agree, that logical, its kinda one side perspective, when you developing it :)
So you suggest:
Folder has unused assets -> Show
Folder does not have unused assets, and its not empty -> Hide
Folder does not have unused assets and its empty -> Hide

Right?

Yeah, that would make the most sense to me. After all, the purpose of this view is to drill down on unused assets and nothing else, so folders that have no unused assets are not relevant

I was thinking about seperate view for empty folders, but its kinda redundant.
Now i am thinking about adding seperate tab for assets that has external referencers (Outside "/Game" folder).

Like if you created some Blueprint in "Engine Folder" content and then used static meshes from "/Game" folder.

That's interesting, thinking about it I don't remember ever encountering such a case (game content referenced from engine). I'd expect that view to be empty for basically all projects, but you never know, might be useful for sanity checking/debug.

If that the case it most likely accidental I think. I encountered it , in one of our project, artist just moved asset to wrong folder, then I couldnt find that asset, until traced it with reference viewer :)
Like you said it more like validation check for assets to be in their proper location.

Hi @Zeblote
I recently worked on this issue, but came to problem when trying to hide folders in PathPicker.
Seems like engine module ContentBrowser dont have any public API that would accept path as exclude options. Those functions are internal for ContentBrowser module itself. I tried to understand how for example Show Engine Content check box works, and tried to implement it, but turns out its hard coded in engine code.
Here is some code examples

// file Engine\Source\Editor\ContentBrowserData\Public\ContentBrowserDataFilter.h
/** Flags controlling which item attributes should be included */
UENUM()
enum class EContentBrowserItemAttributeFilter : uint8
{
	IncludeNone = 0,
	IncludeProject = 1<<0,
	IncludeEngine = 1<<1,
	IncludePlugins = 1<<2,
	IncludeDeveloper = 1<<3,
	IncludeLocalized = 1<<4,
	IncludeAll = IncludeProject | IncludeEngine | IncludePlugins | IncludeDeveloper | IncludeLocalized,
};
ENUM_CLASS_FLAGS(EContentBrowserItemAttributeFilter);

and SPathView class that are responsible for ContentBrowser path UI

const UContentBrowserSettings* ContentBrowserSettings = GetDefault<UContentBrowserSettings>();

	FContentBrowserDataFilter DataFilter;
	DataFilter.bRecursivePaths = true;

	DataFilter.ItemTypeFilter = EContentBrowserItemTypeFilter::IncludeFolders;

	DataFilter.ItemCategoryFilter = InitialCategoryFilter;
	if (bAllowClassesFolder && ContentBrowserSettings->GetDisplayCppFolders())
	{
		DataFilter.ItemCategoryFilter |= EContentBrowserItemCategoryFilter::IncludeClasses;
	}
	else
	{
		DataFilter.ItemCategoryFilter &= ~EContentBrowserItemCategoryFilter::IncludeClasses;
	}
	DataFilter.ItemCategoryFilter &= ~EContentBrowserItemCategoryFilter::IncludeCollections;
	
	DataFilter.ItemAttributeFilter = EContentBrowserItemAttributeFilter::IncludeProject
		| (ContentBrowserSettings->GetDisplayEngineFolder() ? EContentBrowserItemAttributeFilter::IncludeEngine : EContentBrowserItemAttributeFilter::IncludeNone)
		| (ContentBrowserSettings->GetDisplayPluginFolders() ? EContentBrowserItemAttributeFilter::IncludePlugins : EContentBrowserItemAttributeFilter::IncludeNone)
		| (ContentBrowserSettings->GetDisplayDevelopersFolder() ? EContentBrowserItemAttributeFilter::IncludeDeveloper : EContentBrowserItemAttributeFilter::IncludeNone)
		| (ContentBrowserSettings->GetDisplayL10NFolder() ? EContentBrowserItemAttributeFilter::IncludeLocalized : EContentBrowserItemAttributeFilter::IncludeNone);

	TSharedPtr<FBlacklistPaths> CombinedFolderBlacklist;
	if ((FolderBlacklist && FolderBlacklist->HasFiltering()) || (WritableFolderBlacklist && WritableFolderBlacklist->HasFiltering() && !bAllowReadOnlyFolders))
	{
		CombinedFolderBlacklist = MakeShared<FBlacklistPaths>();
		if (FolderBlacklist)
		{
			CombinedFolderBlacklist->Append(*FolderBlacklist);
		}
		if (WritableFolderBlacklist && !bAllowReadOnlyFolders)
		{
			CombinedFolderBlacklist->Append(*WritableFolderBlacklist);
		}
	}

	if (PluginPathFilters.IsValid() && PluginPathFilters->Num() > 0 && ContentBrowserSettings->GetDisplayPluginFolders())
	{
		TArray<TSharedRef<IPlugin>> Plugins = IPluginManager::Get().GetEnabledPluginsWithContent();
		for (const TSharedRef<IPlugin>& Plugin : Plugins)
		{
			if (!PluginPathFilters->PassesAllFilters(Plugin))
			{
				FString MountedAssetPath = Plugin->GetMountedAssetPath();
				MountedAssetPath.RemoveFromEnd(TEXT("/"), ESearchCase::CaseSensitive);

				if (!CombinedFolderBlacklist.IsValid())
				{
					CombinedFolderBlacklist = MakeShared<FBlacklistPaths>();
				}
				CombinedFolderBlacklist->AddBlacklistItem("PluginPathFilters", MountedAssetPath);
			}
		}
	}

	ContentBrowserUtils::AppendAssetFilterToContentBrowserFilter(FARFilter(), nullptr, CombinedFolderBlacklist, DataFilter);

	FContentBrowserDataCompiledFilter CompiledDataFilter;
	{
		static const FName RootPath = "/";
		UContentBrowserDataSubsystem* ContentBrowserData = IContentBrowserDataModule::Get().GetSubsystem();
		ContentBrowserData->CompileFilter(RootPath, DataFilter, CompiledDataFilter);
	}
	return CompiledDataFilter;

BlacklistItems maybe solution, but its kinda private to module :(

So to implement this we have 2 options.

  • change engine code, which its not an option if I want plugin be compatible and available in marketplace
  • create custom ContentBrowserUI

Second option maybe solution, but it will take too much time on development, I think its not worth the effort for this feature.

PS. I will keep this issue open, if someone will help me with this.

Thanks

Now Empty folders can be hidden in unreal engine 5 content browser settings.