Files
UnrealEngineUWP/Engine/Plugins/Runtime/ModelViewViewModel/Source/ModelViewViewModelDebugger/Private/MVVMDebugSnapshot.cpp
patrick boutot fa42c9b609 MVVM: Rework for the view runtime data. The new format allows for better error detection and new features in progress. The view owns the bindings and events. The source has a list of the bindings. That saves runtime of memory, the delegate doesn't store the binding id. All bindings, events, sources are now sorted for better incremental build performance.
Add a different "key" structures to prevent mistakes with indexes.
Unregister the delay bindings when the source is released.
Store the FieldId, in the source itself. That reduces the amount of work when loading the view.
Add option to delay the events initialization (like we do for bindings).
The binding to evaluate "long path" view models are now separated from regular bindings.
#jira UE-194167
#rb editor-ui-systems

[CL 30042205 by patrick boutot in ue5-main branch]
2023-12-01 11:13:35 -05:00

175 lines
6.7 KiB
C++

// Copyright Epic Games, Inc. All Rights Reserved.
#include "MVVMDebugSnapshot.h"
#include "MVVMDebugView.h"
#include "MVVMDebugViewClass.h"
#include "Bindings/MVVMCompiledBindingLibrary.h"
#include "Blueprint/UserWidget.h"
#include "Engine/LocalPlayer.h"
#include "Engine/World.h"
#include "Templates/ValueOrError.h"
#include "MVVMDebugView.h"
#include "MVVMDebugViewModel.h"
#include "MVVMViewModelBase.h"
#include "UObject/UObjectIterator.h"
#include "View/MVVMView.h"
#include "View/MVVMViewClass.h"
namespace UE::MVVM
{
namespace Private
{
FMVVMViewSourceDebugEntry CreateSourceInstanceEntry(const UMVVMView* View, const FMVVMView_Source& ViewSource)
{
FMVVMViewSourceDebugEntry Result;
Result.SourceInstanceName = View->GetViewClass()->GetSource(ViewSource.ClassKey).GetName();
Result.SourceAsset = ViewSource.Source ? FAssetData(ViewSource.Source->GetClass()) : FAssetData();
Result.ViewModelDebugId = FGuid::NewGuid();
Result.LiveSource = ViewSource.Source;
return Result;
}
FMVVMViewBindingDebugEntry CreateViewBindingDebugEntry(const UMVVMViewClass* ViewClass, const FMVVMViewClass_Binding& Binding, int32 Index)
{
FMVVMViewBindingDebugEntry Result;
#if WITH_EDITOR
Result.BlueprintViewBindingId = Binding.GetEditorId();
#endif
if (ViewClass->GetBindingLibrary().IsLoaded())
{
if (Binding.GetBinding().GetSourceFieldPath().IsValid())
{
TValueOrError<FString, FString> SourceFieldPathValue = ViewClass->GetBindingLibrary().FieldPathToString(Binding.GetBinding().GetSourceFieldPath(), false);
Result.SourceFieldPath = SourceFieldPathValue.HasValue() ? SourceFieldPathValue.StealValue() : SourceFieldPathValue.StealError();
}
if (Binding.GetBinding().GetDestinationFieldPath().IsValid())
{
TValueOrError<FString, FString> DestinationFieldPathValue = ViewClass->GetBindingLibrary().FieldPathToString(Binding.GetBinding().GetDestinationFieldPath(), false);
Result.DestinationFieldPath = DestinationFieldPathValue.HasValue() ? DestinationFieldPathValue.StealValue() : DestinationFieldPathValue.StealError();
}
if (Binding.GetBinding().GetConversionFunctionFieldPath().IsValid())
{
TValueOrError<FString, FString> ConversionFieldPathValue = ViewClass->GetBindingLibrary().FieldPathToString(Binding.GetBinding().GetConversionFunctionFieldPath(), false);
Result.ConversionFunctionFieldPath = ConversionFieldPathValue.HasValue() ? ConversionFieldPathValue.StealValue() : ConversionFieldPathValue.StealError();
}
}
Result.CompiledBindingIndex = Index;
return Result;
}
FMVVMViewModelFieldBoundDebugEntry CreateViewModelFieldBoundDebugEntry(const UE::FieldNotification::FFieldMulticastDelegate::FDelegateView& DelegateView)
{
FMVVMViewModelFieldBoundDebugEntry Result;
Result.KeyObjectName = DelegateView.KeyObject ? DelegateView.KeyObject->GetFName() : FName();
Result.KeyFieldId = FFieldNotificationId(DelegateView.KeyField.GetName());
Result.BindingFunctionName = DelegateView.BindingFunctionName;
Result.BindingObjectPathName = DelegateView.BindingObject ? DelegateView.BindingObject->GetPathName() : FString();
Result.LiveInstanceKeyObject = DelegateView.KeyObject;
Result.LiveInstanceBindingObject = DelegateView.BindingObject;
return Result;
}
}//namespace private
TSharedPtr<FMVVMViewDebugEntry> FDebugSnapshot::FindView(FGuid Id) const
{
const TSharedPtr<FMVVMViewDebugEntry>* Result = Views.FindByPredicate([Id](const TSharedPtr<FMVVMViewDebugEntry>& Other){ return Other->ViewInstanceDebugId == Id; });
return Result ? *Result : TSharedPtr<FMVVMViewDebugEntry>();
}
TSharedPtr<FMVVMViewModelDebugEntry> FDebugSnapshot::FindViewModel(FGuid Id) const
{
const TSharedPtr<FMVVMViewModelDebugEntry>* Result = ViewModels.FindByPredicate([Id](const TSharedPtr<FMVVMViewModelDebugEntry>& Other) { return Other->ViewModelDebugId == Id; });
return Result ? *Result : TSharedPtr<FMVVMViewModelDebugEntry>();
}
TSharedPtr<FDebugSnapshot> FDebugSnapshot::CreateSnapshot()
{
TSharedPtr<FDebugSnapshot> Snapshot = MakeShared<FDebugSnapshot>();
for (FThreadSafeObjectIterator It(UMVVMView::StaticClass()); It; ++It)
{
if (It->IsTemplate(RF_ClassDefaultObject))
{
continue;
}
UMVVMView* View = CastChecked<UMVVMView>(*It);
UUserWidget* UserWidget = View->GetOuterUUserWidget();
TSharedPtr<FMVVMViewDebugEntry> DebugEntry = MakeShared<FMVVMViewDebugEntry>();
if (UserWidget)
{
DebugEntry->UserWidgetInstanceName = UserWidget->GetFName();
ULocalPlayer* LocalPlayer = UserWidget->GetOwningLocalPlayer();
DebugEntry->LocalPlayerName = LocalPlayer ? LocalPlayer->GetFName() : FName();
UWorld* World = UserWidget->GetWorld();
DebugEntry->WorldName = World ? World->GetFName() : FName();
DebugEntry->UserWidgetAsset = FAssetData(UserWidget->GetClass());
}
for (const FMVVMView_Source& ViewSource : View->GetSources())
{
DebugEntry->Sources.Add(Private::CreateSourceInstanceEntry(View, ViewSource));
}
DebugEntry->ViewClassDebugId = Snapshot->FindOrAddViewClassEntry(View->GetViewClass())->ViewClassDebugId;
DebugEntry->ViewInstanceDebugId = FGuid::NewGuid();
DebugEntry->LiveView = View;
Snapshot->Views.Add(DebugEntry);
}
for (FThreadSafeObjectIterator It(UMVVMViewModelBase::StaticClass()); It; ++It)
{
if (It->IsTemplate(RF_ClassDefaultObject))
{
continue;
}
UMVVMViewModelBase* ViewModel = CastChecked<UMVVMViewModelBase>(*It);
TSharedPtr<FMVVMViewModelDebugEntry> DebugEntry = MakeShared<FMVVMViewModelDebugEntry>();
DebugEntry->Name = ViewModel->GetFName();
DebugEntry->PathName = ViewModel->GetPathName();
DebugEntry->ViewModelAsset = FAssetData(ViewModel->GetClass());
for (const UE::FieldNotification::FFieldMulticastDelegate::FDelegateView& DelegateView : ViewModel->GetNotificationDelegateView())
{
DebugEntry->FieldBound.Add(Private::CreateViewModelFieldBoundDebugEntry(DelegateView));
}
//DebugEntry.PropertyBag;
DebugEntry->ViewModelDebugId = FGuid::NewGuid();
DebugEntry->LiveViewModel = ViewModel;
Snapshot->ViewModels.Add(DebugEntry);
}
return Snapshot;
}
TSharedRef<FMVVMViewClassDebugEntry> FDebugSnapshot::FindOrAddViewClassEntry(const UMVVMViewClass* ViewClass)
{
TSharedPtr<FMVVMViewClassDebugEntry>* Entry = ViewClasses.FindByPredicate([ViewClass](const TSharedPtr<FMVVMViewClassDebugEntry>& Entry) { return Entry->LiveViewClass == ViewClass; });
if (Entry)
{
return Entry->ToSharedRef();
}
TSharedRef<FMVVMViewClassDebugEntry> NewEntry = MakeShared<FMVVMViewClassDebugEntry>();
ViewClasses.Add(NewEntry);
NewEntry->ViewClassDebugId = FGuid::NewGuid();
NewEntry->LiveViewClass = ViewClass;
int32 Index = 0;
for (const FMVVMViewClass_Binding& Binding : ViewClass->GetBindings())
{
NewEntry->Bindings.Add(Private::CreateViewBindingDebugEntry(ViewClass, Binding, Index));
++Index;
}
return NewEntry;
}
}//namespace UE::MVVM