void SDetailsView::RemoveDeletedObjects( const TArray<UObject*>& DeletedObjects )
{
	TArray< TWeakObjectPtr< UObject > > NewObjectList;
	bool bObjectsRemoved = false;

	for(const TSharedPtr<FComplexPropertyNode>& ComplexRootNode : RootPropertyNodes)
	{
		FObjectPropertyNode* RootPropertyNode = ComplexRootNode->AsObjectNode();
		// Scan all objects and look for objects which need to be replaced
		for ( TPropObjectIterator Itor( RootPropertyNode->ObjectIterator() ); Itor; ++Itor )
		{
			if( DeletedObjects.Contains( Itor->Get() ) )
			{
				// An object we had needs to be removed
				bObjectsRemoved = true;
			}
			else
			{
				// If the deleted object list does not contain the current object, its ok to keep it in the list
				NewObjectList.Add( Itor->Get() );
			}
		}
	}

	// if any objects were replaced update the observed objects
	if( bObjectsRemoved )
	{
		SetObjectArrayPrivate( NewObjectList );
	}
}
TSharedRef<SWidget> SPropertyEditorEditInline::GenerateClassPicker()
{
	FClassViewerInitializationOptions Options;
	Options.bShowUnloadedBlueprints = true;
	Options.bShowDisplayNames = true;
	Options.bShowNoneOption = true;

	TSharedPtr<FPropertyEditorInlineClassFilter> ClassFilter = MakeShareable( new FPropertyEditorInlineClassFilter );
	Options.ClassFilter = ClassFilter;
	ClassFilter->bAllowAbstract = false;

	const TSharedRef< FPropertyNode > PropertyNode = PropertyEditor->GetPropertyNode();
	UProperty* Property = PropertyNode->GetProperty();
	ClassFilter->ObjProperty = Cast<UObjectPropertyBase>( Property );
	ClassFilter->IntProperty = Cast<UInterfaceProperty>( Property );

	FObjectPropertyNode* ObjectPropertyNode = PropertyNode->FindObjectItemParent();
	if( ObjectPropertyNode )
	{
		for ( TPropObjectIterator Itor( ObjectPropertyNode->ObjectIterator() ); Itor; ++Itor )
		{
			UObject* OwnerObject = Itor->Get();
			ClassFilter->LimitToIsAOfAllObjects.Add( OwnerObject );
		}
	}

	Options.PropertyHandle = PropertyEditor->GetPropertyHandle();

	FOnClassPicked OnPicked( FOnClassPicked::CreateRaw( this, &SPropertyEditorEditInline::OnClassPicked ) );

	return FModuleManager::LoadModuleChecked<FClassViewerModule>("ClassViewer").CreateClassViewer(Options, OnPicked);
}
void SDetailsView::RemoveInvalidObjects()
{
	TArray< TWeakObjectPtr< UObject > > ResetArray;

	bool bAllFound = true;
	
	for(const TSharedPtr<FComplexPropertyNode>& ComplexRootNode : RootPropertyNodes)
	{
		FObjectPropertyNode* RootPropertyNode = ComplexRootNode->AsObjectNode();
		if(RootPropertyNode)
		{
			for(TPropObjectIterator Itor(RootPropertyNode->ObjectIterator()); Itor; ++Itor)
			{
				TWeakObjectPtr<UObject> Object = *Itor;

				if(Object.IsValid() && !Object->IsPendingKill())
				{
					ResetArray.Add(Object);
				}
				else
				{
					bAllFound = false;
				}
			}
		}
	}

	if (!bAllFound)
	{
		SetObjectArrayPrivate(ResetArray);
	}
}
void SDetailsView::SetObjectPackageOverrides(const TMap<TWeakObjectPtr<UObject>, TWeakObjectPtr<UPackage>>& InMapping)
{
	for(TSharedPtr<FComplexPropertyNode>& ComplexRootNode : RootPropertyNodes)
	{
		FObjectPropertyNode* RootNode = ComplexRootNode->AsObjectNode();
		if(RootNode)
		{
			RootNode->SetObjectPackageOverrides(InMapping);
		}
	}
}
/** Called at the end of SetObjectArray after we change the objects being observed */
void SDetailsView::PostSetObject()
{
	DestroyColorPicker();
	ColorPropertyNode = nullptr;

	FPropertyNodeInitParams InitParams;
	InitParams.ParentNode = nullptr;
	InitParams.Property = nullptr;
	InitParams.ArrayOffset = 0;
	InitParams.ArrayIndex = INDEX_NONE;
	InitParams.bAllowChildren = true;
	InitParams.bForceHiddenPropertyVisibility =  FPropertySettings::Get().ShowHiddenProperties();

	switch ( DetailsViewArgs.DefaultsOnlyVisibility )
	{
	case FDetailsViewArgs::EEditDefaultsOnlyNodeVisibility::Hide:
		InitParams.bCreateDisableEditOnInstanceNodes = false;
		break;
	case FDetailsViewArgs::EEditDefaultsOnlyNodeVisibility::Show:
		InitParams.bCreateDisableEditOnInstanceNodes = true;
		break;
	case FDetailsViewArgs::EEditDefaultsOnlyNodeVisibility::Automatic:
		InitParams.bCreateDisableEditOnInstanceNodes = HasClassDefaultObject();
		break;
	default:
		check(false);
	}

	for( TSharedPtr<FComplexPropertyNode>& ComplexRootNode : RootPropertyNodes )
	{
		FObjectPropertyNode* RootPropertyNode = ComplexRootNode->AsObjectNode();

		RootPropertyNode->InitNode( InitParams );

		// Restore existing expanded items
		RestoreExpandedItems(ComplexRootNode.ToSharedRef());
	}

	UpdatePropertyMaps();

	for( auto ExternalRootNode : ExternalRootPropertyNodes )
	{
		if( ExternalRootNode.IsValid() )
		{
			RestoreExpandedItems( ExternalRootNode.Pin().ToSharedRef() );
		}
	}

	UpdateFilteredDetails();
}
/** Called before during SetObjectArray before we change the objects being observed */
void SDetailsView::PreSetObject(int32 InNewNumObjects)
{
	// Save existing expanded items first
	for(TSharedPtr<FComplexPropertyNode>& RootNode : RootPropertyNodes)
	{
		SaveExpandedItems(RootNode.ToSharedRef());

		RootNodesPendingKill.Add(RootNode);
		FObjectPropertyNode* RootObjectNode = RootNode->AsObjectNode();
		RootObjectNode->RemoveAllObjects();
		RootObjectNode->ClearCachedReadAddresses(true);
		RootObjectNode->ClearObjectPackageOverrides();
	}

	for( auto ExternalRootNode : ExternalRootPropertyNodes )
	{
		if( ExternalRootNode.IsValid() )
		{
			SaveExpandedItems( ExternalRootNode.Pin().ToSharedRef() );

			FComplexPropertyNode* ComplexNode = ExternalRootNode.Pin()->AsComplexNode();
			if(ComplexNode)
			{
				ComplexNode->Disconnect();
			}
		}
	}

	ExternalRootPropertyNodes.Empty();
	RootPropertyNodes.Empty(InNewNumObjects);

	if(DetailsViewArgs.bAllowMultipleTopLevelObjects)
	{
		for(int32 NewRootIndex = 0; NewRootIndex < InNewNumObjects; ++NewRootIndex)
		{
			RootPropertyNodes.Add(MakeShareable(new FObjectPropertyNode));
		}
	}
	else
	{
		RootPropertyNodes.Add(MakeShareable(new FObjectPropertyNode));
	}	


	SelectedActors.Empty();
	SelectedObjects.Empty();
}
void SDetailsView::ReplaceObjects( const TMap<UObject*, UObject*>& OldToNewObjectMap )
{
	TArray< TWeakObjectPtr< UObject > > NewObjectList;
	bool bObjectsReplaced = false;

	TArray< FObjectPropertyNode* > ObjectNodes;
	for(TSharedPtr<FComplexPropertyNode>& RootNode : RootPropertyNodes)
	{
		PropertyEditorHelpers::CollectObjectNodes(RootNode, ObjectNodes );
	}

	for( int32 ObjectNodeIndex = 0; ObjectNodeIndex < ObjectNodes.Num(); ++ObjectNodeIndex )
	{
		FObjectPropertyNode* CurrentNode = ObjectNodes[ObjectNodeIndex];

		// Scan all objects and look for objects which need to be replaced
		for ( TPropObjectIterator Itor( CurrentNode->ObjectIterator() ); Itor; ++Itor )
		{
			UObject* Replacement = OldToNewObjectMap.FindRef( Itor->Get() );
			if( Replacement && Replacement->GetClass() == Itor->Get()->GetClass() )
			{
				bObjectsReplaced = true;
				if( CurrentNode->IsRootNode() )
				{
					// Note: only root objects count for the new object list. Sub-Objects (i.e components count as needing to be replaced but they don't belong in the top level object list
					NewObjectList.Add( Replacement );
				}
			}
			else if( CurrentNode->IsRootNode() )
			{
				// Note: only root objects count for the new object list. Sub-Objects (i.e components count as needing to be replaced but they don't belong in the top level object list
				NewObjectList.Add( Itor->Get() );
			}
		}
	}


	if( bObjectsReplaced )
	{
		SetObjectArrayPrivate( NewObjectList );
	}

}
void SPropertyEditorEditInline::OnClassPicked(UClass* InClass)
{
	TArray<FObjectBaseAddress> ObjectsToModify;
	TArray<FString> NewValues;

	const TSharedRef< FPropertyNode > PropertyNode = PropertyEditor->GetPropertyNode();
	FObjectPropertyNode* ObjectNode = PropertyNode->FindObjectItemParent();

	if( ObjectNode )
	{
		for ( TPropObjectIterator Itor( ObjectNode->ObjectIterator() ) ; Itor ; ++Itor )
		{
			FString NewValue;
			if (InClass)
			{
				UObject*		Object = Itor->Get();
				UObject*		UseOuter = (InClass->IsChildOf(UClass::StaticClass()) ? Cast<UClass>(Object)->GetDefaultObject() : Object);
				EObjectFlags	MaskedOuterFlags = UseOuter ? UseOuter->GetMaskedFlags(RF_PropagateToSubObjects) : RF_NoFlags;
				if (UseOuter && UseOuter->HasAnyFlags(RF_ClassDefaultObject | RF_ArchetypeObject))
				{
					MaskedOuterFlags |= RF_ArchetypeObject;
				}
				UObject*		NewObject = StaticConstructObject(InClass, UseOuter, NAME_None, MaskedOuterFlags, NULL);

				NewValue = NewObject->GetPathName();
			}
			else
			{
				NewValue = FName(NAME_None).ToString();
			}
			NewValues.Add(NewValue);
		}

		const TSharedRef< IPropertyHandle > PropertyHandle = PropertyEditor->GetPropertyHandle();
		PropertyHandle->SetPerObjectValues( NewValues );

		// Force a rebuild of the children when this node changes
		PropertyNode->RequestRebuildChildren();

		ComboButton->SetIsOpen(false);
	}
}
void SDetailsViewBase::SetColorPropertyFromColorPicker(FLinearColor NewColor)
{
	const TSharedPtr< FPropertyNode > PinnedColorPropertyNode = ColorPropertyNode.Pin();
	if (ensure(PinnedColorPropertyNode.IsValid()))
	{
		UProperty* Property = PinnedColorPropertyNode->GetProperty();
		check(Property);

		FObjectPropertyNode* ObjectNode = PinnedColorPropertyNode->FindObjectItemParent();

		if (ObjectNode && ObjectNode->GetNumObjects())
		{
			FScopedTransaction Transaction(NSLOCTEXT("UnrealEd", "SetColorProperty", "Set Color Property"));

			PinnedColorPropertyNode->NotifyPreChange(Property, GetNotifyHook());

			FPropertyChangedEvent ChangeEvent(Property, EPropertyChangeType::ValueSet);
			PinnedColorPropertyNode->NotifyPostChange(ChangeEvent, GetNotifyHook());
		}
	}
}
void FDetailLayoutBuilderImpl::GetObjectsBeingCustomized( TArray< TWeakObjectPtr<UObject> >& OutObjects ) const
{
	OutObjects.Empty();

	// The class to find properties in defaults to the class currently being customized
	FName ClassName = CurrentCustomizationClass ? CurrentCustomizationClass->GetFName() : NAME_None;
	
	if( ClassName != NAME_None && CurrentCustomizationVariableName != NAME_None )
	{
		// If this fails there are no properties associated with the class name provided
		FClassInstanceToPropertyMap* ClassInstanceToPropertyMapPtr = PropertyMap.Find( ClassName );

		if( ClassInstanceToPropertyMapPtr )
		{
			FClassInstanceToPropertyMap& ClassInstanceToPropertyMap = *ClassInstanceToPropertyMapPtr;
		
			FPropertyNodeMap* PropertyNodeMapPtr = ClassInstanceToPropertyMap.Find( CurrentCustomizationVariableName );

			if( PropertyNodeMapPtr )
			{
				FPropertyNodeMap& PropertyNodeMap = *PropertyNodeMapPtr;
				FObjectPropertyNode* ParentObjectProperty = PropertyNodeMap.ParentProperty ? PropertyNodeMap.ParentProperty->AsObjectNode() : NULL;
				if (ParentObjectProperty)
				{
					for (int32 ObjectIndex = 0; ObjectIndex < ParentObjectProperty->GetNumObjects(); ++ObjectIndex)
					{
						OutObjects.Add(ParentObjectProperty->GetUObject(ObjectIndex));
					}
				}
			}
		}
	}
	else
	{
		OutObjects = DetailsView.GetSelectedObjects();
	}
}
void SDetailsView::ForceRefresh()
{
	TArray< TWeakObjectPtr< UObject > > NewObjectList;

	const FRootPropertyNodeList& RootNodes = GetRootNodes();
	for(const TSharedPtr<FComplexPropertyNode>& ComplexRootNode : RootNodes)
	{
		FObjectPropertyNode* RootNode = ComplexRootNode->AsObjectNode();
		if(RootNode)
		{
			// Simply re-add the same existing objects to cause a refresh
			for(TPropObjectIterator Itor(RootNode->ObjectIterator()); Itor; ++Itor)
			{
				TWeakObjectPtr<UObject> Object = *Itor;
				if(Object.IsValid())
				{
					NewObjectList.Add(Object.Get());
				}
			}
		}
	}

	SetObjectArrayPrivate( NewObjectList );
}
void SDetailsViewBase::UpdateSinglePropertyMapRecursive(FPropertyNode& InNode, FDetailLayoutData& LayoutData, FName CurCategory, FComplexPropertyNode* CurObjectNode, bool bEnableFavoriteSystem, bool bUpdateFavoriteSystemOnly)
{
	FDetailLayoutBuilderImpl& DetailLayout = *LayoutData.DetailLayout;

	UProperty* ParentProperty = InNode.GetProperty();
	UStructProperty* ParentStructProp = Cast<UStructProperty>(ParentProperty);
	for(int32 ChildIndex = 0; ChildIndex < InNode.GetNumChildNodes(); ++ChildIndex)
	{
		//Use the original value for each child
		bool LocalUpdateFavoriteSystemOnly = bUpdateFavoriteSystemOnly;

		TSharedPtr<FPropertyNode> ChildNodePtr = InNode.GetChildNode(ChildIndex);
		FPropertyNode& ChildNode = *ChildNodePtr;
		UProperty* Property = ChildNode.GetProperty();

		{
			FObjectPropertyNode* ObjNode = ChildNode.AsObjectNode();
			FCategoryPropertyNode* CategoryNode = ChildNode.AsCategoryNode();
			if(ObjNode)
			{
				// Currently object property nodes do not provide any useful information other than being a container for its children.  We do not draw anything for them.
				// When we encounter object property nodes, add their children instead of adding them to the tree.
				UpdateSinglePropertyMapRecursive(ChildNode, LayoutData, CurCategory, ObjNode, bEnableFavoriteSystem, LocalUpdateFavoriteSystemOnly);
			}
			else if(CategoryNode)
			{
				if(!LocalUpdateFavoriteSystemOnly)
				{
					FName InstanceName = NAME_None;
					FName CategoryName = CurCategory;
					FString CategoryDelimiterString;
					CategoryDelimiterString.AppendChar(FPropertyNodeConstants::CategoryDelimiterChar);
					if(CurCategory != NAME_None && CategoryNode->GetCategoryName().ToString().Contains(CategoryDelimiterString))
					{
						// This property is child of another property so add it to the parent detail category
						FDetailCategoryImpl& CategoryImpl = DetailLayout.DefaultCategory(CategoryName);
						CategoryImpl.AddPropertyNode(ChildNodePtr.ToSharedRef(), InstanceName);
					}
				}

				// For category nodes, we just set the current category and recurse through the children
				UpdateSinglePropertyMapRecursive(ChildNode, LayoutData, CategoryNode->GetCategoryName(), CurObjectNode, bEnableFavoriteSystem, LocalUpdateFavoriteSystemOnly);
			}
			else
			{
				// Whether or not the property can be visible in the default detail layout
				bool bVisibleByDefault = IsVisibleStandaloneProperty(ChildNode, InNode);

				// Whether or not the property is a struct
				UStructProperty* StructProperty = Cast<UStructProperty>(Property);

				bool bIsStruct = StructProperty != NULL;

				static FName ShowOnlyInners("ShowOnlyInnerProperties");

				bool bIsChildOfCustomizedStruct = false;
				bool bIsCustomizedStruct = false;

				const UStruct* Struct = StructProperty ? StructProperty->Struct : NULL;
				const UStruct* ParentStruct = ParentStructProp ? ParentStructProp->Struct : NULL;
				if(Struct || ParentStruct)
				{
					FPropertyEditorModule& ParentPlugin = FModuleManager::GetModuleChecked<FPropertyEditorModule>("PropertyEditor");
					if(Struct)
					{
						bIsCustomizedStruct = ParentPlugin.IsCustomizedStruct(Struct, SharedThis(this));
					}

					if(ParentStruct)
					{
						bIsChildOfCustomizedStruct = ParentPlugin.IsCustomizedStruct(ParentStruct, SharedThis(this));
					}
				}

				// Whether or not to push out struct properties to their own categories or show them inside an expandable struct 
				bool bPushOutStructProps = bIsStruct && !bIsCustomizedStruct && !ParentStructProp && Property->HasMetaData(ShowOnlyInners);

				// Is the property edit inline new 
				const bool bIsEditInlineNew = ChildNode.HasNodeFlags(EPropertyNodeFlags::ShowInnerObjectProperties) || SPropertyEditorEditInline::Supports(&ChildNode, ChildNode.GetArrayIndex());

				// Is this a property of a container property
				bool bIsChildOfContainer = PropertyEditorHelpers::IsChildOfArray(ChildNode) || PropertyEditorHelpers::IsChildOfSet(ChildNode) || PropertyEditorHelpers::IsChildOfMap(ChildNode);

				// Edit inline new properties should be visible by default
				bVisibleByDefault |= bIsEditInlineNew;

				// Children of arrays are not visible directly,
				bVisibleByDefault &= !bIsChildOfContainer;

				FPropertyAndParent PropertyAndParent(*Property, ParentProperty);
				const bool bIsUserVisible = IsPropertyVisible(PropertyAndParent);

				// Inners of customized in structs should not be taken into consideration for customizing.  They are not designed to be individually customized when their parent is already customized
				if(!bIsChildOfCustomizedStruct && !LocalUpdateFavoriteSystemOnly)
				{
					// Add any object classes with properties so we can ask them for custom property layouts later
					LayoutData.ClassesWithProperties.Add(Property->GetOwnerStruct());
				}

				// If there is no outer object then the class is the object root and there is only one instance
				FName InstanceName = NAME_None;
				if(CurObjectNode && CurObjectNode->GetParentNode())
				{
					InstanceName = CurObjectNode->GetParentNode()->GetProperty()->GetFName();
				}
				else if(ParentStructProp)
				{
					InstanceName = ParentStructProp->GetFName();
				}

				// Do not add children of customized in struct properties or arrays
				if(!bIsChildOfCustomizedStruct && !bIsChildOfContainer && !LocalUpdateFavoriteSystemOnly)
				{
					// Get the class property map
					FClassInstanceToPropertyMap& ClassInstanceMap = LayoutData.ClassToPropertyMap.FindOrAdd(Property->GetOwnerStruct()->GetFName());

					FPropertyNodeMap& PropertyNodeMap = ClassInstanceMap.FindOrAdd(InstanceName);

					if(!PropertyNodeMap.ParentProperty)
					{
						PropertyNodeMap.ParentProperty = CurObjectNode;
					}
					else
					{
						ensure(PropertyNodeMap.ParentProperty == CurObjectNode);
					}

					checkSlow(!PropertyNodeMap.Contains(Property->GetFName()));

					PropertyNodeMap.Add(Property->GetFName(), ChildNodePtr);
				}
				bool bCanDisplayFavorite = false;
				if(bVisibleByDefault && bIsUserVisible && !bPushOutStructProps)
				{
					FName CategoryName = CurCategory;
					// For properties inside a struct, add them to their own category unless they just take the name of the parent struct.  
					// In that case push them to the parent category
					FName PropertyCatagoryName = FObjectEditorUtils::GetCategoryFName(Property);
					if(!ParentStructProp || (PropertyCatagoryName != ParentStructProp->Struct->GetFName()))
					{
						CategoryName = PropertyCatagoryName;
					}

					if(!LocalUpdateFavoriteSystemOnly)
					{
						if(IsPropertyReadOnly(PropertyAndParent))
						{
							ChildNode.SetNodeFlags(EPropertyNodeFlags::IsReadOnly, true);
						}

						// Add a property to the default category
						FDetailCategoryImpl& CategoryImpl = DetailLayout.DefaultCategory(CategoryName);
						CategoryImpl.AddPropertyNode(ChildNodePtr.ToSharedRef(), InstanceName);
					}

					bCanDisplayFavorite = true;
					if(bEnableFavoriteSystem)
					{
						if(bIsCustomizedStruct)
						{
							bCanDisplayFavorite = false;
							//CustomizedStruct child are not categorize since they are under an object but we have to put them in favorite category if the user want to favorite them
							LocalUpdateFavoriteSystemOnly = true;
						}
						else if(ChildNodePtr->IsFavorite())
						{
							//Find or create the favorite category, we have to duplicate favorite property row under this category
							FString CategoryFavoritesName = TEXT("Favorites");
							FName CatFavName = *CategoryFavoritesName;
							FDetailCategoryImpl& CategoryFavImpl = DetailLayout.DefaultCategory(CatFavName);
							CategoryFavImpl.SetSortOrder(0);
							CategoryFavImpl.SetCategoryAsSpecialFavorite();

							//Add the property to the favorite
							FObjectPropertyNode *RootObjectParent = ChildNodePtr->FindRootObjectItemParent();
							FName RootInstanceName = NAME_None;
							if(RootObjectParent != nullptr)
							{
								RootInstanceName = RootObjectParent->GetObjectBaseClass()->GetFName();
							}

							if(LocalUpdateFavoriteSystemOnly)
							{
								if(IsPropertyReadOnly(PropertyAndParent))
								{
									ChildNode.SetNodeFlags(EPropertyNodeFlags::IsReadOnly, true);
								}
								else
								{
									//If the parent has a condition that is not met, make the child as readonly
									FDetailLayoutCustomization ParentTmpCustomization;
									ParentTmpCustomization.PropertyRow = MakeShareable(new FDetailPropertyRow(InNode.AsShared(), CategoryFavImpl.AsShared()));
									if(ParentTmpCustomization.PropertyRow->GetPropertyEditor()->IsPropertyEditingEnabled() == false)
									{
										ChildNode.SetNodeFlags(EPropertyNodeFlags::IsReadOnly, true);
									}
								}
							}

							//Duplicate the row
							CategoryFavImpl.AddPropertyNode(ChildNodePtr.ToSharedRef(), RootInstanceName);
						}

						if(bIsStruct)
						{
							LocalUpdateFavoriteSystemOnly = true;
						}
					}
				}
				ChildNodePtr->SetCanDisplayFavorite(bCanDisplayFavorite);

				bool bRecurseIntoChildren =
					!bIsChildOfCustomizedStruct // Don't recurse into built in struct children, we already know what they are and how to display them
					&&  !bIsCustomizedStruct // Don't recurse into customized structs
					&&	!bIsChildOfContainer // Do not recurse into containers, the children are drawn by the container property parent
					&&	!bIsEditInlineNew // Edit inline new children are not supported for customization yet
					&&	bIsUserVisible // Properties must be allowed to be visible by a user if they are not then their children are not visible either
					&& (!bIsStruct || bPushOutStructProps); //  Only recurse into struct properties if they are going to be displayed as standalone properties in categories instead of inside an expandable area inside a category

				if(bRecurseIntoChildren || LocalUpdateFavoriteSystemOnly)
				{
					// Built in struct properties or children of arras 
					UpdateSinglePropertyMapRecursive(ChildNode, LayoutData, CurCategory, CurObjectNode, bEnableFavoriteSystem, LocalUpdateFavoriteSystemOnly);
				}
			}
		}
	}
}
void SDetailsView::SetObjectArrayPrivate(const TArray< TWeakObjectPtr< UObject > >& InObjects)
{
	double StartTime = FPlatformTime::Seconds();

	PreSetObject(InObjects.Num());

	// Selected actors for building SelectedActorInfo
	TArray<AActor*> SelectedRawActors;

	bViewingClassDefaultObject = InObjects.Num() > 0 ? true : false;
	bool bOwnedByLockedLevel = false;
	for( int32 ObjectIndex = 0 ; ObjectIndex < InObjects.Num(); ++ObjectIndex )
	{
		TWeakObjectPtr< UObject > Object = InObjects[ObjectIndex];

		if( Object.IsValid() )
		{
			bViewingClassDefaultObject &= Object->HasAnyFlags( RF_ClassDefaultObject );

			if(DetailsViewArgs.bAllowMultipleTopLevelObjects)
			{
				check(RootPropertyNodes.Num() == InObjects.Num());
				RootPropertyNodes[ObjectIndex]->AsObjectNode()->AddObject( Object.Get() );
			}
			else
			{
				RootPropertyNodes[0]->AsObjectNode()->AddObject( Object.Get() );
			}

			SelectedObjects.Add( Object );
			AActor* Actor = Cast<AActor>( Object.Get() );
			if( Actor )
			{
				SelectedActors.Add( Actor );
				SelectedRawActors.Add( Actor );
			}
		}
	}

	if( InObjects.Num() == 0 )
	{
		// Unlock the view automatically if we are viewing nothing
		bIsLocked = false;
	}

	// Selection changed, refresh the detail area
	if ( DetailsViewArgs.NameAreaSettings != FDetailsViewArgs::ActorsUseNameArea && DetailsViewArgs.NameAreaSettings != FDetailsViewArgs::ComponentsAndActorsUseNameArea )
	{
		NameArea->Refresh( SelectedObjects );
	}
	else
	{
		NameArea->Refresh( SelectedActors, SelectedObjects, DetailsViewArgs.NameAreaSettings );
	}
	
	// When selection changes rebuild information about the selection
	SelectedActorInfo = AssetSelectionUtils::BuildSelectedActorInfo( SelectedRawActors );

	// @todo Slate Property Window
	//SetFlags(EPropertyWindowFlags::ReadOnly, bOwnedByLockedLevel);


	PostSetObject();

	// Set the title of the window based on the objects we are viewing
	// Or call the delegate for handling when the title changed
	FString Title;

	if( GetNumObjects() == 0 )
	{
		Title = NSLOCTEXT("PropertyView", "NothingSelectedTitle", "Nothing selected").ToString();
	}
	else if( GetNumObjects() == 1 && RootPropertyNodes[0]->AsObjectNode()->GetNumObjects() > 0)
	{
		// if the object is the default metaobject for a UClass, use the UClass's name instead
		UObject* Object = RootPropertyNodes[0]->AsObjectNode()->GetUObject(0);
		FString ObjectName = Object->GetName();
		if ( Object->GetClass()->GetDefaultObject() == Object )
		{
			ObjectName = Object->GetClass()->GetName();
		}
		else
		{
			// Is this an actor?  If so, it might have a friendly name to display
			const AActor* Actor = Cast<const  AActor >( Object );
			if( Actor != nullptr)
			{
				// Use the friendly label for this actor
				ObjectName = Actor->GetActorLabel();
			}
		}

		Title = ObjectName;
	}
	else if(DetailsViewArgs.bAllowMultipleTopLevelObjects)
	{
		Title = FString::Printf(*NSLOCTEXT("PropertyView", "MultipleToLevelObjectsSelected", "%i selected").ToString(), GetNumObjects());
	}
	else
	{
		FObjectPropertyNode* RootPropertyNode = RootPropertyNodes[0]->AsObjectNode();
		Title = FString::Printf( *NSLOCTEXT("PropertyView", "MultipleSelected", "%s (%i selected)").ToString(), *RootPropertyNode->GetObjectBaseClass()->GetName(), RootPropertyNode->GetNumObjects() );
	}

	OnObjectArrayChanged.ExecuteIfBound(Title, InObjects);

	double ElapsedTime = FPlatformTime::Seconds() - StartTime;
}
bool SDetailsView::ShouldSetNewObjects(const TArray< TWeakObjectPtr< UObject > >& InObjects) const
{
	bool bShouldSetObjects = false;

	const bool bHadBSPBrushSelected = SelectedActorInfo.bHaveBSPBrush;
	if( bHadBSPBrushSelected == true )
	{
		// If a BSP brush was selected we need to refresh because surface could have been selected and the object set not updated
		bShouldSetObjects = true;
	}
	else if( InObjects.Num() != GetNumObjects() )
	{
		// If the object arrays differ in size then at least one object is different so we must reset
		bShouldSetObjects = true;
	}
	else if(InObjects.Num() == 0)
	{
		// User is likely resetting details panel
		bShouldSetObjects = true;
	}
	else
	{
		// Check to see if the objects passed in are different. If not we do not need to set anything
		TSet< TWeakObjectPtr< UObject > > NewObjects;
		NewObjects.Append(InObjects);

		if(DetailsViewArgs.bAllowMultipleTopLevelObjects)
		{
			
			// For multiple top level node support, if the single object in each node is not found in the new object set
			// then we need to refresh
			for(int32 RootNodeIndex = 0; RootNodeIndex < RootPropertyNodes.Num(); ++RootNodeIndex)
			{
				FObjectPropertyNode* RootPropertyNode = RootPropertyNodes[RootNodeIndex]->AsObjectNode();
				
				if(RootPropertyNode && RootPropertyNode->GetNumObjects() > 0)
				{
					if(!NewObjects.Contains(RootPropertyNode->GetUObject(0)))
					{
						bShouldSetObjects = true;
						break;
					}
				}
				else
				{
					bShouldSetObjects = true;
					break;
				}
			}
		}
		else
		{

			ensure(RootPropertyNodes.Num() == 1);
			FObjectPropertyNode* RootPropertyNode = RootPropertyNodes[0]->AsObjectNode();
			if( RootPropertyNode )
			{
				for(TPropObjectIterator Itor(RootPropertyNode->ObjectIterator()); Itor; ++Itor)
				{
					TWeakObjectPtr<UObject> Object = *Itor;
					if(Object.IsValid() && !NewObjects.Contains(Object))
					{
						// An existing object is not in the list of new objects to set
						bShouldSetObjects = true;
						break;
					}
					else if(!Object.IsValid())
					{
						// An existing object is invalid
						bShouldSetObjects = true;
						break;
					}
				}
			}
			else
			{
				bShouldSetObjects = true;
			}
		}
	}
	
	if (!bShouldSetObjects && AssetSelectionUtils::IsAnySurfaceSelected(nullptr))
	{
		bShouldSetObjects = true;
	}

	return bShouldSetObjects;
}