617 lines
23 KiB
C++
617 lines
23 KiB
C++
// Copyright Epic Games, Inc. All Rights Reserved.
|
|
|
|
#include "AssetSystemContentBrowserInfoProvider.h"
|
|
|
|
#include "ActorFolder.h"
|
|
#include "ActorFolderDesc.h"
|
|
#include "Algo/Sort.h"
|
|
#include "AssetDefinition.h"
|
|
#include "AssetDefinitionAssetInfo.h"
|
|
#include "AssetDefinitionRegistry.h"
|
|
#include "AssetRegistry/AssetRegistryModule.h"
|
|
#include "AssetToolsModule.h"
|
|
#include "AssetViewTypes.h"
|
|
#include "AutoReimport/AssetSourceFilenameCache.h"
|
|
#include "CollectionManagerModule.h"
|
|
#include "Containers/VersePath.h"
|
|
#include "ContentBrowserDataSource.h"
|
|
#include "ContentBrowserUtils.h"
|
|
#include "IAssetTools.h"
|
|
#include "ICollectionContainer.h"
|
|
#include "ICollectionManager.h"
|
|
#include "Misc/EngineBuildSettings.h"
|
|
|
|
#define LOCTEXT_NAMESPACE "AssetSystemContentBrowserInfoProvider"
|
|
|
|
FAssetSystemContentBrowserInfoProvider::FAssetSystemContentBrowserInfoProvider(const TSharedPtr<FAssetViewItem>& InAssetItem)
|
|
: AssetItem(InAssetItem)
|
|
{
|
|
if (AssetItem.IsValid())
|
|
{
|
|
OnItemDataChangedCacheDisplayTagsDelegateHandle = AssetItem->OnItemDataChanged().AddRaw(this, &FAssetSystemContentBrowserInfoProvider::CacheDisplayTags);
|
|
OnItemDataChangedCacheDirtyExternalPackageDelegateHandle = AssetItem->OnItemDataChanged().AddRaw(this, &FAssetSystemContentBrowserInfoProvider::CacheDirtyExternalPackageInfo);
|
|
}
|
|
FAssetData AssetData;
|
|
AssetItem->GetItem().Legacy_TryGetAssetData(AssetData);
|
|
if (AssetData.IsValid())
|
|
{
|
|
if (const UAssetDefinition* AssetDefinition = UAssetDefinitionRegistry::Get()->GetAssetDefinitionForAsset(AssetData))
|
|
{
|
|
bShouldSaveExternalPackages = AssetDefinition->ShouldSaveExternalPackages();
|
|
}
|
|
}
|
|
CacheDisplayTags();
|
|
}
|
|
|
|
FAssetSystemContentBrowserInfoProvider::~FAssetSystemContentBrowserInfoProvider()
|
|
{
|
|
if (AssetItem.IsValid())
|
|
{
|
|
AssetItem->OnItemDataChanged().Remove(OnItemDataChangedCacheDisplayTagsDelegateHandle);
|
|
AssetItem->OnItemDataChanged().Remove(OnItemDataChangedCacheDirtyExternalPackageDelegateHandle);
|
|
OnItemDataChangedCacheDisplayTagsDelegateHandle.Reset();
|
|
OnItemDataChangedCacheDirtyExternalPackageDelegateHandle.Reset();
|
|
}
|
|
}
|
|
|
|
void FAssetSystemContentBrowserInfoProvider::PopulateAssetInfo(TArray<FAssetDisplayInfo>& OutAssetDisplayInfo) const
|
|
{
|
|
if (AssetItem->IsFile())
|
|
{
|
|
// The tooltip contains the name, class, path, asset registry tags and source control status
|
|
FText PublicStateText;
|
|
const FSlateBrush* PublicStateIcon = nullptr;
|
|
|
|
// Create a box to hold every line of info in the body of the tooltip
|
|
TSharedRef<SVerticalBox> InfoBox = SNew(SVerticalBox);
|
|
|
|
FAssetData ItemAssetData;
|
|
AssetItem->GetItem().Legacy_TryGetAssetData(ItemAssetData);
|
|
|
|
// TODO: Always use the virtual path?
|
|
FAssetDisplayInfo PathInfo = FAssetDisplayInfo();
|
|
PathInfo.StatusTitle = LOCTEXT("TileViewTooltipPath", "Path");
|
|
if (ItemAssetData.IsValid())
|
|
{
|
|
PathInfo.StatusDescription = FText::FromName(ItemAssetData.PackagePath);
|
|
}
|
|
else
|
|
{
|
|
PathInfo.StatusDescription = FText::FromName(AssetItem->GetItem().GetVirtualPath());
|
|
}
|
|
OutAssetDisplayInfo.Add(PathInfo);
|
|
|
|
if (ItemAssetData.IsValid() && FAssetToolsModule::GetModule().Get().ShowingContentVersePath())
|
|
{
|
|
UE::Core::FVersePath VersePath = ItemAssetData.GetVersePath();
|
|
if (VersePath.IsValid())
|
|
{
|
|
FAssetDisplayInfo& VersePathInfo = OutAssetDisplayInfo.AddDefaulted_GetRef();
|
|
VersePathInfo.StatusTitle = LOCTEXT("TileViewTooltipVersePath", "Verse Path");
|
|
VersePathInfo.StatusDescription = FText::FromString(VersePath.ToString());
|
|
}
|
|
}
|
|
|
|
if (ItemAssetData.IsValid() && ItemAssetData.PackageName != NAME_None)
|
|
{
|
|
const FString PackagePathWithinRoot = ContentBrowserUtils::GetPackagePathWithinRoot(ItemAssetData.PackageName.ToString());
|
|
int32 PackageNameLength = PackagePathWithinRoot.Len();
|
|
|
|
int32 MaxAssetPathLen = ContentBrowserUtils::GetMaxAssetPathLen();
|
|
|
|
// Asset Path Length Info
|
|
FAssetDisplayInfo AssetPathLengthInfo = FAssetDisplayInfo();
|
|
AssetPathLengthInfo.StatusTitle = LOCTEXT("TileViewTooltipAssetPathLengthKey", "Asset Filepath Length");
|
|
AssetPathLengthInfo.StatusDescription = FText::Format(LOCTEXT("TileViewTooltipAssetPathLengthValue", "{0} / {1}"), FText::AsNumber(PackageNameLength), FText::AsNumber(MaxAssetPathLen));
|
|
OutAssetDisplayInfo.Add(AssetPathLengthInfo);
|
|
|
|
int32 PackageNameLengthForCooking = ContentBrowserUtils::GetPackageLengthForCooking(ItemAssetData.PackageName.ToString(), FEngineBuildSettings::IsInternalBuild());
|
|
|
|
// Cook Path Length Info
|
|
int32 MaxCookPathLen = ContentBrowserUtils::GetMaxCookPathLen();
|
|
FAssetDisplayInfo CookPathLenInfo = FAssetDisplayInfo();
|
|
CookPathLenInfo.StatusTitle = LOCTEXT("TileViewTooltipPathLengthForCookingKey", "Cooking Filepath Length");
|
|
CookPathLenInfo.StatusDescription = FText::Format(LOCTEXT("TileViewTooltipPathLengthForCookingValue", "{0} / {1}"), FText::AsNumber(PackageNameLengthForCooking), FText::AsNumber(MaxCookPathLen));
|
|
OutAssetDisplayInfo.Add(CookPathLenInfo);
|
|
|
|
if (ItemAssetData.GetAssetAccessSpecifier() == EAssetAccessSpecifier::Public)
|
|
{
|
|
PublicStateText = LOCTEXT("PublicAssetState", "Public");
|
|
}
|
|
else if (ItemAssetData.GetAssetAccessSpecifier() == EAssetAccessSpecifier::EpicInternal)
|
|
{
|
|
PublicStateText = LOCTEXT("EpicInternalAssetState", "Epic Internal");
|
|
}
|
|
else
|
|
{
|
|
PublicStateText = LOCTEXT("PrivateAssetState", "Private");
|
|
}
|
|
}
|
|
|
|
if (!AssetItem->GetItem().CanEdit())
|
|
{
|
|
if(AssetItem->GetItem().CanView())
|
|
{
|
|
PublicStateText = LOCTEXT("ViewReadOnlyAssetState", "View / Read Only");
|
|
PublicStateIcon = FAppStyle::GetBrush("AssetEditor.ReadOnlyOpenable");
|
|
|
|
}
|
|
else
|
|
{
|
|
PublicStateText = LOCTEXT("ReadOnlyAssetState", "Read Only");
|
|
PublicStateIcon = FAppStyle::GetBrush("Icons.Lock");
|
|
}
|
|
}
|
|
|
|
if(!AssetItem->GetItem().IsSupported())
|
|
{
|
|
PublicStateText = LOCTEXT("UnsupportedAssetState", "Unsupported");
|
|
}
|
|
|
|
// Add tags
|
|
for (const FTagContentBrowserDisplayItem& DisplayTagItem : CachedDisplayTags)
|
|
{
|
|
FAssetDisplayInfo DisplayTagInfo = FAssetDisplayInfo();
|
|
DisplayTagInfo.StatusTitle = DisplayTagItem.DisplayKey;
|
|
DisplayTagInfo.StatusDescription = DisplayTagItem.DisplayValue;
|
|
OutAssetDisplayInfo.Add(DisplayTagInfo);
|
|
}
|
|
|
|
// Add asset source files
|
|
if (ItemAssetData.IsValid())
|
|
{
|
|
TOptional<FAssetImportInfo> ImportInfo = FAssetSourceFilenameCache::ExtractAssetImportInfo(ItemAssetData);
|
|
if (ImportInfo.IsSet())
|
|
{
|
|
for (const FAssetImportInfo::FSourceFile& File : ImportInfo->SourceFiles)
|
|
{
|
|
FText SourceLabel = LOCTEXT("TileViewTooltipSourceFile", "Source File");
|
|
if (File.DisplayLabelName.Len() > 0)
|
|
{
|
|
SourceLabel = FText::FromString(FText(LOCTEXT("TileViewTooltipSourceFile", "Source File")).ToString() + TEXT(" (") + File.DisplayLabelName + TEXT(")"));
|
|
}
|
|
FAssetDisplayInfo SourceFileInfo = FAssetDisplayInfo();
|
|
SourceFileInfo.StatusTitle = SourceLabel;
|
|
SourceFileInfo.StatusDescription = FText::FromString(File.RelativeFilename);
|
|
OutAssetDisplayInfo.Add(SourceFileInfo);
|
|
}
|
|
}
|
|
}
|
|
|
|
static const IConsoleVariable* EnablePublicAssetFeatureCVar = IConsoleManager::Get().FindConsoleVariable(TEXT("AssetTools.EnablePublicAssetFeature"));
|
|
const bool bIsPublicAssetUIEnabled = EnablePublicAssetFeatureCVar && EnablePublicAssetFeatureCVar->GetBool();
|
|
|
|
// Restriction Info
|
|
FAssetDisplayInfo RestrictionInfo = FAssetDisplayInfo();
|
|
RestrictionInfo.IsVisible = PublicStateIcon && bIsPublicAssetUIEnabled && !PublicStateText.IsEmpty() ? EVisibility::Visible : EVisibility::Collapsed;
|
|
RestrictionInfo.StatusIcon = PublicStateIcon;
|
|
RestrictionInfo.StatusTitle = LOCTEXT("Restriction", "Restriction");
|
|
RestrictionInfo.StatusDescription = PublicStateText;
|
|
OutAssetDisplayInfo.Add(RestrictionInfo);
|
|
|
|
// Unsupported Info
|
|
FAssetDisplayInfo UnsupportedInfo = FAssetDisplayInfo();
|
|
UnsupportedInfo.IsVisible = AssetItem->GetItem().IsSupported() ? EVisibility::Collapsed : EVisibility::Visible;;
|
|
UnsupportedInfo.StatusTitle = LOCTEXT("UnsupportedAssetTitleText", "Item is not supported");
|
|
UnsupportedInfo.StatusDescription = LOCTEXT("UnsupportedAssetDescriptionText", "This type of asset is not allowed in this project. Delete unsupported assets to avoid errors.");
|
|
OutAssetDisplayInfo.Add(UnsupportedInfo);
|
|
|
|
// External Package Info
|
|
FAssetDisplayInfo ExternalPackageInfo = FAssetDisplayInfo();
|
|
ExternalPackageInfo.IsVisible = bShouldSaveExternalPackages && !GetExternalPackagesText().IsEmpty() ? EVisibility::Visible : EVisibility::Collapsed;;
|
|
ExternalPackageInfo.StatusTitle = LOCTEXT("DirtyExternalPackages", "Modified external packages");
|
|
ExternalPackageInfo.StatusDescription = GetExternalPackagesText();
|
|
OutAssetDisplayInfo.Add(ExternalPackageInfo);
|
|
|
|
// User Description
|
|
FAssetDisplayInfo UserDescriptionInfo = FAssetDisplayInfo();
|
|
UserDescriptionInfo.IsVisible = GetAssetUserDescription().IsEmpty() ? EVisibility::Collapsed : EVisibility::Visible;;
|
|
UserDescriptionInfo.StatusTitle = LOCTEXT("UserDescriptionTitle", "User Description");
|
|
UserDescriptionInfo.StatusDescription = GetAssetUserDescription();
|
|
OutAssetDisplayInfo.Add(UserDescriptionInfo);
|
|
|
|
// Collection Pips
|
|
if (ItemAssetData.IsValid())
|
|
{
|
|
ICollectionManager& CollectionManager = FCollectionManagerModule::GetModule().Get();
|
|
|
|
TArray<TSharedPtr<ICollectionContainer>> CollectionContainers;
|
|
CollectionManager.GetVisibleCollectionContainers(CollectionContainers);
|
|
|
|
TArray<FCollectionNameType> CollectionsContainingObject;
|
|
for (const TSharedPtr<ICollectionContainer>& CollectionContainer : CollectionContainers)
|
|
{
|
|
CollectionsContainingObject.Reset();
|
|
CollectionContainer->GetCollectionsContainingObject(ItemAssetData.ToSoftObjectPath(), CollectionsContainingObject);
|
|
|
|
Algo::Sort(CollectionsContainingObject, [](const FCollectionNameType& A, const FCollectionNameType& B)
|
|
{
|
|
int32 result = A.Name.Compare(B.Name);
|
|
return result < 0 || (result == 0 && A.Type < B.Type);
|
|
});
|
|
|
|
bool bAddedCollectionHeader = false;
|
|
for (const FCollectionNameType& CollectionContainingObject : CollectionsContainingObject)
|
|
{
|
|
FCollectionStatusInfo CollectionStatusInfo;
|
|
if (CollectionContainer->GetCollectionStatusInfo(CollectionContainingObject.Name, CollectionContainingObject.Type, CollectionStatusInfo))
|
|
{
|
|
if (!bAddedCollectionHeader)
|
|
{
|
|
// StatusTitle currently used to add a separator for status, need to be changed in future version to allow more configurability
|
|
bAddedCollectionHeader = true;
|
|
FAssetDisplayInfo CollectionHeader = FAssetDisplayInfo();
|
|
CollectionHeader.StatusTitle = LOCTEXT("CollectionHeaderTitle", "Collection(s)");
|
|
CollectionHeader.StatusDescription = FText::GetEmpty();
|
|
OutAssetDisplayInfo.Add(CollectionHeader);
|
|
}
|
|
|
|
FAssetDisplayInfo CollectionInfo = FAssetDisplayInfo();
|
|
CollectionInfo.StatusTitle = FText::FromName(CollectionContainingObject.Name);
|
|
CollectionInfo.StatusDescription = FText::AsNumber(CollectionStatusInfo.NumObjects);
|
|
OutAssetDisplayInfo.Add(CollectionInfo);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
void FAssetSystemContentBrowserInfoProvider::CacheDisplayTags()
|
|
{
|
|
CachedDisplayTags.Reset();
|
|
|
|
const FContentBrowserItemDataAttributeValues AssetItemAttributes = AssetItem->GetItem().GetItemAttributes(/*bIncludeMetaData*/true);
|
|
|
|
FAssetData ItemAssetData;
|
|
AssetItem->GetItem().Legacy_TryGetAssetData(ItemAssetData);
|
|
|
|
// Add all visible attributes
|
|
for (const auto& AssetItemAttributePair : AssetItemAttributes)
|
|
{
|
|
const FName AttributeName = AssetItemAttributePair.Key;
|
|
const FContentBrowserItemDataAttributeValue& AttributeValue = AssetItemAttributePair.Value;
|
|
const FContentBrowserItemDataAttributeMetaData& AttributeMetaData = AttributeValue.GetMetaData();
|
|
|
|
if (AttributeMetaData.AttributeType == UObject::FAssetRegistryTag::TT_Hidden)
|
|
{
|
|
continue;
|
|
}
|
|
|
|
// Build the display value for this attribute
|
|
FText DisplayValue;
|
|
if (AttributeValue.GetValueType() == EContentBrowserItemDataAttributeValueType::Text)
|
|
{
|
|
DisplayValue = AttributeValue.GetValueText();
|
|
}
|
|
else
|
|
{
|
|
const FString AttributeValueStr = AttributeValue.GetValue<FString>();
|
|
|
|
auto ReformatNumberStringForDisplay = [](const FString& InNumberString) -> FText
|
|
{
|
|
// Respect the number of decimal places in the source string when converting for display
|
|
int32 NumDecimalPlaces = 0;
|
|
{
|
|
int32 DotIndex = INDEX_NONE;
|
|
if (InNumberString.FindChar(TEXT('.'), DotIndex))
|
|
{
|
|
NumDecimalPlaces = InNumberString.Len() - DotIndex - 1;
|
|
}
|
|
}
|
|
|
|
if (NumDecimalPlaces > 0)
|
|
{
|
|
// Convert the number as a double
|
|
double Num = 0.0;
|
|
LexFromString(Num, *InNumberString);
|
|
|
|
const FNumberFormattingOptions NumFormatOpts = FNumberFormattingOptions()
|
|
.SetMinimumFractionalDigits(NumDecimalPlaces)
|
|
.SetMaximumFractionalDigits(NumDecimalPlaces);
|
|
|
|
return FText::AsNumber(Num, &NumFormatOpts);
|
|
}
|
|
|
|
const bool bIsSigned = InNumberString.Len() > 0 && (InNumberString[0] == TEXT('-') || InNumberString[0] == TEXT('+'));
|
|
if (bIsSigned)
|
|
{
|
|
// Convert the number as a signed int
|
|
int64 Num = 0;
|
|
LexFromString(Num, *InNumberString);
|
|
return FText::AsNumber(Num);
|
|
}
|
|
|
|
// Convert the number as an unsigned int
|
|
uint64 Num = 0;
|
|
LexFromString(Num, *InNumberString);
|
|
return FText::AsNumber(Num);
|
|
};
|
|
|
|
bool bHasSetDisplayValue = false;
|
|
|
|
// Numerical tags need to format the specified number based on the display flags
|
|
if (!bHasSetDisplayValue && AttributeMetaData.AttributeType == UObject::FAssetRegistryTag::TT_Numerical && AttributeValueStr.IsNumeric())
|
|
{
|
|
bHasSetDisplayValue = true;
|
|
|
|
const bool bAsMemory = !!(AttributeMetaData.DisplayFlags & UObject::FAssetRegistryTag::TD_Memory);
|
|
|
|
if (bAsMemory)
|
|
{
|
|
// Memory should be a 64-bit unsigned number of bytes
|
|
uint64 NumBytes = 0;
|
|
LexFromString(NumBytes, *AttributeValueStr);
|
|
|
|
DisplayValue = FText::AsMemory(NumBytes);
|
|
}
|
|
else
|
|
{
|
|
DisplayValue = ReformatNumberStringForDisplay(AttributeValueStr);
|
|
}
|
|
}
|
|
|
|
// Dimensional tags need to be split into their component numbers, with each component number re-formatted
|
|
if (!bHasSetDisplayValue && AttributeMetaData.AttributeType == UObject::FAssetRegistryTag::TT_Dimensional)
|
|
{
|
|
// Formats:
|
|
// 123 (1D)
|
|
// 123x234 (2D)
|
|
// 123x234*345 (2D array)
|
|
// 123x234x345 (3D)
|
|
int32 FirstXPos;
|
|
if (AttributeValueStr.FindChar(TEXT('x'), FirstXPos))
|
|
{
|
|
FString FirstPart = AttributeValueStr.Left(FirstXPos);
|
|
FString Remainder = AttributeValueStr.Mid(FirstXPos + 1);
|
|
int32 RemainderSeparatorPos;
|
|
|
|
if (Remainder.FindChar(TEXT('*'), RemainderSeparatorPos))
|
|
{
|
|
// AxB*C form (2D array)
|
|
FString SecondPart = Remainder.Left(RemainderSeparatorPos);
|
|
FString ThirdPart = Remainder.Mid(RemainderSeparatorPos + 1);
|
|
|
|
bHasSetDisplayValue = true;
|
|
DisplayValue = FText::Format(LOCTEXT("DisplayTag2xArrayFmt", "{0} \u00D7 {1} ({2} elements)"),
|
|
ReformatNumberStringForDisplay(FirstPart),
|
|
ReformatNumberStringForDisplay(SecondPart),
|
|
ReformatNumberStringForDisplay(ThirdPart));
|
|
}
|
|
else if (Remainder.FindChar(TEXT('x'), RemainderSeparatorPos))
|
|
{
|
|
// AxBxC form (3D)
|
|
FString SecondPart = Remainder.Left(RemainderSeparatorPos);
|
|
FString ThirdPart = Remainder.Mid(RemainderSeparatorPos + 1);
|
|
|
|
bHasSetDisplayValue = true;
|
|
DisplayValue = FText::Format(LOCTEXT("DisplayTag3xFmt", "{0} \u00D7 {1} \u00D7 {2}"),
|
|
ReformatNumberStringForDisplay(FirstPart),
|
|
ReformatNumberStringForDisplay(SecondPart),
|
|
ReformatNumberStringForDisplay(ThirdPart));
|
|
}
|
|
else
|
|
{
|
|
// 2D form by default
|
|
bHasSetDisplayValue = true;
|
|
DisplayValue = FText::Format(LOCTEXT("DisplayTag2xFmt", "{0} \u00D7 {1}"),
|
|
ReformatNumberStringForDisplay(FirstPart),
|
|
ReformatNumberStringForDisplay(Remainder));
|
|
}
|
|
}
|
|
else
|
|
{
|
|
// No separators, assume 1D
|
|
bHasSetDisplayValue = true;
|
|
DisplayValue = ReformatNumberStringForDisplay(AttributeValueStr);
|
|
}
|
|
}
|
|
|
|
// Chronological tags need to format the specified timestamp based on the display flags
|
|
if (!bHasSetDisplayValue && AttributeMetaData.AttributeType == UObject::FAssetRegistryTag::TT_Chronological)
|
|
{
|
|
bHasSetDisplayValue = true;
|
|
|
|
FDateTime Timestamp;
|
|
if (FDateTime::Parse(AttributeValueStr, Timestamp))
|
|
{
|
|
const bool bDisplayDate = !!(AttributeMetaData.DisplayFlags & UObject::FAssetRegistryTag::TD_Date);
|
|
const bool bDisplayTime = !!(AttributeMetaData.DisplayFlags & UObject::FAssetRegistryTag::TD_Time);
|
|
const FString TimeZone = (AttributeMetaData.DisplayFlags & UObject::FAssetRegistryTag::TD_InvariantTz) ? FText::GetInvariantTimeZone() : FString();
|
|
|
|
if (bDisplayDate && bDisplayTime)
|
|
{
|
|
DisplayValue = FText::AsDateTime(Timestamp, EDateTimeStyle::Short, EDateTimeStyle::Short, TimeZone);
|
|
}
|
|
else if (bDisplayDate)
|
|
{
|
|
DisplayValue = FText::AsDate(Timestamp, EDateTimeStyle::Short, TimeZone);
|
|
}
|
|
else if (bDisplayTime)
|
|
{
|
|
DisplayValue = FText::AsTime(Timestamp, EDateTimeStyle::Short, TimeZone);
|
|
}
|
|
}
|
|
}
|
|
|
|
// The tag value might be localized text, so we need to parse it for display
|
|
if (!bHasSetDisplayValue && FTextStringHelper::IsComplexText(*AttributeValueStr))
|
|
{
|
|
bHasSetDisplayValue = FTextStringHelper::ReadFromBuffer(*AttributeValueStr, DisplayValue) != nullptr;
|
|
}
|
|
|
|
// Do our best to build something valid from the string value
|
|
if (!bHasSetDisplayValue)
|
|
{
|
|
bHasSetDisplayValue = true;
|
|
|
|
// Since all we have at this point is a string, we can't be very smart here.
|
|
// We need to strip some noise off class paths in some cases, but can't load the asset to inspect its UPROPERTYs manually due to performance concerns.
|
|
FString ValueString = FPackageName::ExportTextPathToObjectPath(AttributeValueStr);
|
|
|
|
const TCHAR StringToRemove[] = TEXT("/Script/");
|
|
if (ValueString.StartsWith(StringToRemove))
|
|
{
|
|
// Remove the class path for native classes, and also remove Engine. for engine classes
|
|
const int32 SizeOfPrefix = UE_ARRAY_COUNT(StringToRemove) - 1;
|
|
ValueString.MidInline(SizeOfPrefix, ValueString.Len() - SizeOfPrefix, EAllowShrinking::No);
|
|
ValueString.ReplaceInline(TEXT("Engine."), TEXT(""));
|
|
}
|
|
|
|
if (ItemAssetData.IsValid())
|
|
{
|
|
if (const UClass* AssetClass = ItemAssetData.GetClass())
|
|
{
|
|
if (const FProperty* TagField = FindFProperty<FProperty>(AssetClass, AttributeName))
|
|
{
|
|
const FProperty* TagProp = nullptr;
|
|
const UEnum* TagEnum = nullptr;
|
|
if (const FByteProperty* ByteProp = CastField<FByteProperty>(TagField))
|
|
{
|
|
TagProp = ByteProp;
|
|
TagEnum = ByteProp->Enum;
|
|
}
|
|
else if (const FEnumProperty* EnumProp = CastField<FEnumProperty>(TagField))
|
|
{
|
|
TagProp = EnumProp;
|
|
TagEnum = EnumProp->GetEnum();
|
|
}
|
|
|
|
// Strip off enum prefixes if they exist
|
|
if (TagProp)
|
|
{
|
|
if (TagEnum)
|
|
{
|
|
const FString EnumPrefix = TagEnum->GenerateEnumPrefix();
|
|
if (EnumPrefix.Len() && ValueString.StartsWith(EnumPrefix))
|
|
{
|
|
ValueString.RightChopInline(EnumPrefix.Len() + 1, EAllowShrinking::No); // +1 to skip over the underscore
|
|
}
|
|
}
|
|
|
|
ValueString = FName::NameToDisplayString(ValueString, false);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
DisplayValue = FText::AsCultureInvariant(MoveTemp(ValueString));
|
|
}
|
|
|
|
// Add suffix to the value, if one is defined for this tag
|
|
if (!AttributeMetaData.Suffix.IsEmpty())
|
|
{
|
|
DisplayValue = FText::Format(LOCTEXT("DisplayTagSuffixFmt", "{0} {1}"), DisplayValue, AttributeMetaData.Suffix);
|
|
}
|
|
}
|
|
|
|
if (!DisplayValue.IsEmpty())
|
|
{
|
|
CachedDisplayTags.Add(FTagContentBrowserDisplayItem(AttributeName, AttributeMetaData.DisplayName, DisplayValue, AttributeMetaData.bIsImportant));
|
|
}
|
|
}
|
|
}
|
|
|
|
void FAssetSystemContentBrowserInfoProvider::CacheDirtyExternalPackageInfo()
|
|
{
|
|
if (bShouldSaveExternalPackages)
|
|
{
|
|
CachedDirtyExternalPackagesList.Empty();
|
|
|
|
FAssetData AssetData;
|
|
AssetItem->GetItem().Legacy_TryGetAssetData(AssetData);
|
|
if (AssetData.IsAssetLoaded())
|
|
{
|
|
if(const UObject* Asset = AssetData.GetAsset())
|
|
{
|
|
if (const UPackage* Package = Asset->GetPackage())
|
|
{
|
|
TArray<UPackage*> ExternalPackages = Package->GetExternalPackages();
|
|
IAssetRegistry& AssetRegistry = FModuleManager::GetModuleChecked<FAssetRegistryModule>(TEXT("AssetRegistry")).Get();
|
|
|
|
// Mirrored/copied from SSourceControlCommon.cpp
|
|
auto RetrieveAssetName = [](const FAssetData& InAssetData) -> FString
|
|
{
|
|
static const FName NAME_ActorLabel(TEXT("ActorLabel"));
|
|
if (InAssetData.FindTag(NAME_ActorLabel))
|
|
{
|
|
FString ResultAssetName;
|
|
InAssetData.GetTagValue(NAME_ActorLabel, ResultAssetName);
|
|
return ResultAssetName;
|
|
}
|
|
|
|
if (InAssetData.FindTag(FPrimaryAssetId::PrimaryAssetDisplayNameTag))
|
|
{
|
|
FString ResultAssetName;
|
|
InAssetData.GetTagValue(FPrimaryAssetId::PrimaryAssetDisplayNameTag, ResultAssetName);
|
|
return ResultAssetName;
|
|
}
|
|
|
|
if (InAssetData.AssetClassPath == UActorFolder::StaticClass()->GetClassPathName())
|
|
{
|
|
FString ActorFolderPath = UActorFolder::GetAssetRegistryInfoFromPackage(InAssetData.PackageName).GetDisplayName();
|
|
if (!ActorFolderPath.IsEmpty())
|
|
{
|
|
return ActorFolderPath;
|
|
}
|
|
}
|
|
|
|
return InAssetData.AssetName.ToString();
|
|
};
|
|
|
|
for (const UPackage* ExternalPackage : ExternalPackages)
|
|
{
|
|
if (ExternalPackage->IsDirty())
|
|
{
|
|
TArray<FAssetData> DirtyAssetDataEntries;
|
|
AssetRegistry.GetAssetsByPackageName(*ExternalPackage->GetName(), DirtyAssetDataEntries);
|
|
|
|
if (CachedDirtyExternalPackagesList.Len())
|
|
{
|
|
CachedDirtyExternalPackagesList.Append("\n");
|
|
}
|
|
|
|
CachedDirtyExternalPackagesList.Append(ExternalPackage->GetPathName());
|
|
|
|
for (const FAssetData& DirtyAssetData : DirtyAssetDataEntries)
|
|
{
|
|
const FString AssetName = RetrieveAssetName(DirtyAssetData);
|
|
const FString AssetClass = DirtyAssetData.AssetClassPath.GetAssetName().ToString();
|
|
|
|
CachedDirtyExternalPackagesList.Append("\n\t");
|
|
CachedDirtyExternalPackagesList.Append(FString::Printf(TEXT("%s (%s)"), *AssetName, *AssetClass));
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
FText FAssetSystemContentBrowserInfoProvider::GetExternalPackagesText() const
|
|
{
|
|
if (CachedDirtyExternalPackagesList.Len())
|
|
{
|
|
return FText::FromString(CachedDirtyExternalPackagesList);
|
|
}
|
|
|
|
return FText::GetEmpty();
|
|
}
|
|
|
|
FText FAssetSystemContentBrowserInfoProvider::GetAssetUserDescription() const
|
|
{
|
|
if (AssetItem && AssetItem->IsFile())
|
|
{
|
|
FContentBrowserItemDataAttributeValue DescriptionAttributeValue = AssetItem->GetItem().GetItemAttribute(ContentBrowserItemAttributes::ItemDescription);
|
|
if (DescriptionAttributeValue.IsValid())
|
|
{
|
|
return DescriptionAttributeValue.GetValue<FText>();
|
|
}
|
|
}
|
|
|
|
return FText::GetEmpty();
|
|
}
|
|
|
|
#undef LOCTEXT_NAMESPACE
|