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::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 ); } }
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::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 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 ); }
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; }