/** * fills in the OutAddresses array with the addresses of all of the available objects. * @param InItem The property to get objects from. * @param OutAddresses Storage array for all of the objects' addresses. */ bool FObjectPropertyNode::GetReadAddressUncached( FPropertyNode& InNode, FReadAddressListData& OutAddresses ) const { // Are any objects selected for property editing? if( !GetNumObjects()) { return false; } UProperty* InItemProperty = InNode.GetProperty(); // Is there a InItemProperty bound to the InItemProperty window? if( !InItemProperty ) { return false; } // Write addresses to the output. for ( int32 ObjectIdx = 0 ; ObjectIdx < GetNumObjects() ; ++ObjectIdx ) { const UObject* TempObject = GetUObject(ObjectIdx); if( TempObject != NULL ) { OutAddresses.Add( TempObject, InNode.GetValueBaseAddress( (uint8*)(TempObject) ) ); } } // Everything checked out and we have usable addresses. return true; }
FValueCache( TSharedRef<FPropertyNode> InPropertyNode, UObject* InOwnerObject ) : PropertyNode( InPropertyNode ) { PropertyValueRoot.OwnerObject = InOwnerObject; UProperty* Property = InPropertyNode->GetProperty(); check(Property); check(PropertyValueRoot.OwnerObject); FPropertyNode* ParentNode = InPropertyNode->GetParentNode(); //UArrayProperty* ArrayProp = Cast<UArrayProperty>(Property); UArrayProperty* OuterArrayProp = Cast<UArrayProperty>(Property->GetOuter()); // calculate the values for the current object PropertyValueBaseAddress = OuterArrayProp == NULL ? InPropertyNode->GetValueBaseAddress(PropertyValueRoot.ValueAddress) : ParentNode->GetValueBaseAddress(PropertyValueRoot.ValueAddress); PropertyValueAddress = InPropertyNode->GetValueAddress(PropertyValueRoot.ValueAddress); }
bool FObjectPropertyNode::GetReadAddressUncached(FPropertyNode& InNode, bool InRequiresSingleSelection, FReadAddressListData& OutAddresses, bool bComparePropertyContents, bool bObjectForceCompare, bool bArrayPropertiesCanDifferInSize) const { // Are any objects selected for property editing? if( !GetNumObjects()) { return false; } UProperty* InItemProperty = InNode.GetProperty(); // Is there a InItemProperty bound to the InItemProperty window? if( !InItemProperty ) { return false; } // Requesting a single selection? if( InRequiresSingleSelection && GetNumObjects() > 1) { // Fail: we're editing properties for multiple objects. return false; } //assume all properties are the same unless proven otherwise bool bAllTheSame = true; ////////////////////////////////////////// // If this item is the child of an array, return NULL if there is a different number // of items in the array in different objects, when multi-selecting. if( Cast<UArrayProperty>(InItemProperty->GetOuter()) ) { FPropertyNode* ParentNode = InNode.GetParentNode(); check(ParentNode); const UObject* TempObject = GetUObject(0); if( TempObject ) { uint8* BaseAddr = ParentNode->GetValueBaseAddress( (uint8*)TempObject ); if( BaseAddr ) { const int32 Num = FScriptArrayHelper::Num(BaseAddr); for( int32 ObjIndex = 1 ; ObjIndex < GetNumObjects(); ObjIndex++ ) { TempObject = GetUObject(ObjIndex); BaseAddr = ParentNode->GetValueBaseAddress( (uint8*)TempObject ); if( BaseAddr && Num != FScriptArrayHelper::Num( BaseAddr ) ) { bAllTheSame = false; } } } } } uint8* Base = GetUObject(0) ? InNode.GetValueBaseAddress( (uint8*)(GetUObject(0)) ) : NULL; if (Base) { // If the item is an array itself, return NULL if there are a different number of // items in the array in different objects, when multi-selecting. if( Cast<UArrayProperty>(InItemProperty) ) { // This flag is an override for array properties which want to display e.g. the "Clear" and "Empty" // buttons, even though the array properties may differ in the number of elements. if ( !bArrayPropertiesCanDifferInSize ) { const UObject* TempObject = GetUObject(0); int32 const Num = FScriptArrayHelper::Num(InNode.GetValueBaseAddress( (uint8*)TempObject)); for( int32 ObjIndex = 1 ; ObjIndex < GetNumObjects() ; ObjIndex++ ) { TempObject = GetUObject(ObjIndex); if( TempObject && Num != FScriptArrayHelper::Num(InNode.GetValueBaseAddress((uint8*)TempObject)) ) { bAllTheSame = false; } } } } else { if ( bComparePropertyContents || !Cast<UObjectPropertyBase>(InItemProperty) || bObjectForceCompare ) { // Make sure the value of this InItemProperty is the same in all selected objects. for( int32 ObjIndex = 1 ; ObjIndex < GetNumObjects() ; ObjIndex++ ) { const UObject* TempObject = GetUObject(ObjIndex); if( !InItemProperty->Identical( Base, InNode.GetValueBaseAddress( (uint8*)TempObject ) ) ) { bAllTheSame = false; } } } else { if ( Cast<UObjectPropertyBase>(InItemProperty) ) { // We don't want to exactly compare component properties. However, we // need to be sure that all references are either valid or invalid. // If BaseObj is NON-NULL, all other objects' properties should also be non-NULL. // If BaseObj is NULL, all other objects' properties should also be NULL. UObject* BaseObj = Cast<UObjectPropertyBase>(InItemProperty)->GetObjectPropertyValue(Base); for( int32 ObjIndex = 1 ; ObjIndex < GetNumObjects() ; ObjIndex++ ) { const UObject* TempObject = GetUObject(ObjIndex); UObject* CurObj = Cast<UObjectPropertyBase>(InItemProperty)->GetObjectPropertyValue(InNode.GetValueBaseAddress( (uint8*)TempObject )); if ( ( !BaseObj && CurObj ) // BaseObj is NULL, but this InItemProperty is non-NULL! || ( BaseObj && !CurObj ) ) // BaseObj is non-NULL, but this InItemProperty is NULL! { bAllTheSame = false; } } } } } } // Write addresses to the output. for ( int32 ObjIndex = 0 ; ObjIndex < GetNumObjects(); ++ObjIndex ) { const UObject* TempObject = GetUObject(ObjIndex); if( TempObject ) { OutAddresses.Add( TempObject, InNode.GetValueBaseAddress( (uint8*)(TempObject) ) ); } } // Everything checked out and we have usable addresses. return bAllTheSame; }