// Copyright Epic Games, Inc. All Rights Reserved. #pragma once #include "CoreMinimal.h" #include "Serialization/ArchiveUObject.h" #include "Components/ActorComponent.h" #include "GameFramework/Actor.h" #include "Widgets/DeclarativeSyntaxSupport.h" #include "Input/Reply.h" #include "Widgets/SCompoundWidget.h" #include "Engine/Brush.h" #include "Model.h" #include "Widgets/Views/STableViewBase.h" #include "Widgets/Views/STableRow.h" #include "Widgets/Views/STreeView.h" #include "Engine/Polys.h" class FMenuBuilder; class SWindow; struct FReferenceTreeDataContainer; /** * A struct representing a node in the reference graph */ struct FReferenceGraphNode { /** The object this node represents */ UObject* Object; /** Links from this nodes object. Each link represents a reference to the object. */ TSet Links; /** If the node has been visited while populating the reference tree. This prevents circular references. */ bool bVisited; FReferenceGraphNode( UObject* InObject ) : Object( InObject ), bVisited(false) { } /** * Returns the object that should be displayed on the graph * * @param bShowScriptReferences If true we should return script objects. */ UObject* GetObjectToDisplay( bool bShowScriptReferences ) { UObject* ObjectToDisplay = NULL; // Check to see if the object in this node is a component. If it is try to display the actor that uses it. UActorComponent* Comp = Cast( Object ); if( Comp ) { if( Comp->GetOwner() ) { // Use the components owner if it has one. ObjectToDisplay = Comp->GetOwner(); } else if( Comp->GetOuter() && Comp->GetOuter()->IsA( AActor::StaticClass() ) ) { // Use the components outer if it is an actor ObjectToDisplay = Comp->GetOuter(); } } else if( Object->IsA( UPolys::StaticClass() ) ) { // Special case handling for bsp. // Outer chain: Polys->UModel->ABrush UObject* PossibleModel = Object->GetOuter(); if( PossibleModel && PossibleModel->IsA( UModel::StaticClass() )) { UObject* PossibleBrush = PossibleModel->GetOuter(); if(PossibleBrush && PossibleBrush->IsA( ABrush::StaticClass() ) ) { ObjectToDisplay = PossibleBrush; } } } else { ObjectToDisplay = Object; } if( ObjectToDisplay && ObjectToDisplay->HasAnyFlags( RF_ClassDefaultObject ) && !bShowScriptReferences ) { // Don't return class default objects if we aren't showing script references ObjectToDisplay = NULL; } return ObjectToDisplay; } }; typedef TMap FReferenceGraph; /** * An archive for creating a reference graph of all UObjects */ class FArchiveGenerateReferenceGraph : public FArchiveUObject { public: FArchiveGenerateReferenceGraph( FReferenceGraph& OutGraph ); FArchive& operator<<( UObject*& Object ); private: /** The object currently being serialized. */ UObject* CurrentObject; /** The set of visited objects so we dont serialize something twice. */ TSet< UObject* > VisitedObjects; /** Reference to the graph we are creating. */ FReferenceGraph& ObjectGraph; }; typedef TSharedPtr< struct FReferenceTreeDataContainer > FReferenceTreeItemPtr; typedef STreeView< FReferenceTreeItemPtr > SReferenceTreeView; class SReferenceTree : public SCompoundWidget { public: SLATE_BEGIN_ARGS( SReferenceTree ) : _Object(NULL) {} SLATE_ARGUMENT(UObject*, Object) SLATE_END_ARGS() UNREALED_API void Construct( const FArguments& InArgs ); UNREALED_API ~SReferenceTree(); static UNREALED_API TWeakPtr< SWindow > SingletonInstance; static UNREALED_API void OpenDialog(UObject* InObject); private: /** Generates a row for the tree. */ TSharedRef< ITableRow > OnGenerateRowForReferenceTree( FReferenceTreeItemPtr Item, const TSharedRef< STableViewBase >& OwnerTable ); /** * Populates the tree, for a specific root object * * @param InRootObject The root object to find the references of. * */ void PopulateTree( UObject* RootObject ); /** * Helper function for recursively generating the reference tree * * @param InNode The node to find all references of. * @param InParentNode The generated tree node to parent all references to. * * @return true if any references were found. */ bool PopulateTreeRecursive( FReferenceGraphNode& InNode, FReferenceTreeItemPtr InParentNode ); /** Retrieves the children for a node in the tree. */ void OnGetChildrenForReferenceTree( FReferenceTreeItemPtr InParent, TArray< FReferenceTreeItemPtr >& OutChildren ); /** Builds the context menu widget. */ TSharedPtr< SWidget > BuildMenuWidget(); /** Fills the top menu for the window. */ void FillViewEntries( FMenuBuilder& MenuBuilder ); void FillOptionsEntries( FMenuBuilder& MenuBuilder ); /** * Sets expansions states for every item in the tree. * * @param bInExpandItems true if items should be expanded, false if they should be collapsed. */ void SetAllExpansionStates(bool bInExpansionState); /** * Helper function for recursion to set expansions states for every item in the tree. * * @param InNode The node to recurse into. * @param bInExpandItems true if items should be expanded, false if they should be collapsed. */ void SetAllExpansionStates_Helper(FReferenceTreeItemPtr InNode, bool bInExpansionState); /** Callback when the editor's map changes. */ void OnEditorMapChange(uint32 InMapChangeFlags); /** Cleans up the tree for a refresh. */ void DestroyGraphAndTree(); /** Called when the view properties menu option is chosen. */ void OnMenuViewProperties( AActor* InActor ); /** Called when the show object in editor menu option is chosen. */ void OnMenuShowEditor( UObject* InObject ); /** Toggles show script references and refreshes the tree. */ void OnShowScriptReferences(); /** Callback to see if the Show Script References should be checked. */ bool OnShowScriptReferences_Checked() const { return bShowScriptRefs; } /** Callback when the OK button is clicked. */ FReply OnOK_Clicked(void); /** Sets the window of this dialog. */ void SetWindow( TSharedPtr InWindow ) { MyWindow = InWindow; } private: /** List holding the root object of the tree. */ TArray< FReferenceTreeItemPtr > ReferenceTreeRoot; /** Slate Widget object for the Tree View. */ TSharedPtr< SReferenceTreeView > ReferenceTreeView; /** The reference graph for all UObjects. */ FReferenceGraph ReferenceGraph; /** If the tree should show script references. */ bool bShowScriptRefs; /** Pointer to the containing window. */ TWeakPtr< SWindow > MyWindow; };