public bool TryGetRedirectedProperty(string childName, out InspectorProperty property)
        {
            this.EnsureUpdated();

            property = null;

            if (childName.Length == 0 || childName[0] != '{')
            {
                return(false);
            }

            try
            {
                var key     = (TKey)DictionaryKeyUtility.GetDictionaryKeyValue(childName, typeof(TKey));
                var keyList = this.keys[0];

                for (int i = 0; i < keyList.Count; i++)
                {
                    if (PropertyValueEntry <TKey> .EqualityComparer(key, keyList[i]))
                    {
                        property = this.Property.Children[i].Children["Value"];
                        return(true);
                    }
                }
            }
            catch (Exception) { return(false); }

            return(false);
        }
예제 #2
0
        private void EnsureUpdated()
        {
            if (this.valueEntry.Property.Tree.UpdateID != this.lastUpdateID)
            {
                this.dictIndexMap.Clear();
                this.lastUpdateID = this.valueEntry.Property.Tree.UpdateID;

                for (int i = 0; i < this.keys.Length; i++)
                {
                    // Swap lists and keep the old one for a change comparison
                    var oldKeyList = this.keys[i];
                    var keyList    = this.oldKeys[i];

                    this.oldKeys[i] = oldKeyList;
                    this.keys[i]    = keyList;

                    keyList.Clear();

                    var dict = this.valueEntry.Values[i];

                    if (object.ReferenceEquals(dict, null))
                    {
                        continue;
                    }

                    this.dictIndexMap[dict] = i;

                    var castDict = dict as Dictionary <TKey, TValue>;

                    if (castDict != null)
                    {
                        // Reduce garbage allocation
                        foreach (var pair in castDict.GFIterator())
                        {
                            keyList.Add(pair.Key);
                        }
                    }
                    else
                    {
                        foreach (var key in dict.Keys)
                        {
                            keyList.Add(key);
                        }
                    }

                    if (keyList.Count > 1)
                    {
                        var comparer = DictionaryKeyUtility.KeyComparer <TKey> .Default;

                        var a = keyList[0];
                        for (int j = 1; j < keyList.Count; j++)
                        {
                            var b = keyList[j];
                            if (comparer.Compare(a, b) > 0)
                            {
                                keyList.Sort(comparer);
                                break;
                            }
                            a = b;
                        }
                    }

                    if (keyList.Count != oldKeyList.Count)
                    {
                        this.OnChangedUpdatePaths();
                    }
                    else
                    {
                        for (int j = 0; j < keyList.Count; j++)
                        {
                            if (!PropertyValueEntry <TKey> .EqualityComparer(keyList[j], oldKeyList[j]))
                            {
                                this.OnChangedUpdatePaths();
                                break;
                            }
                        }
                    }
                }
            }
        }
예제 #3
0
        /// <summary>
        /// Sets the actual target tree value.
        /// </summary>
        protected override void SetActualValueImplementation(int index, EditableKeyValuePair <TKey, TValue> value)
        {
            var parentProperty = this.Property.Parent;
            var parentEntry    = (IPropertyValueEntry <TDictionary>)parentProperty.ValueEntry;
            var handler        = (IDictionaryHandler <TKey>)parentEntry.GetDictionaryHandler();
            var dict           = parentEntry.Values[index];

            TKey   oldKey = handler.GetKey(index, this.Property.Index);
            TValue oldValue;

            dict.TryGetValue(oldKey, out oldValue);

            TKey   newKey   = value.Key;
            TValue newValue = value.Value;

            if (!PropertyValueEntry <TKey> .EqualityComparer(oldKey, newKey))
            {
                // Key has changed; ignore if new key already exists in dictionary
                if (dict.ContainsKey(newKey))
                {
                    this.hasTempInvalidKey = true;
                    this.tempInvalidKey    = newKey;
                }
                else
                {
                    bool isPrefab = this.SerializationBackend == SerializationBackend.ODIN && this.Property.Tree.HasPrefabs;

                    this.hasTempInvalidKey = false;
                    this.tempInvalidKey    = default(TKey);

                    dict.Remove(oldKey);
                    dict.Add(newKey, newValue);

                    if (isPrefab && handler.SupportsPrefabModifications)
                    {
                        this.Property.Tree.RegisterPrefabDictionaryRemoveKeyModification(parentProperty, index, oldKey);
                        this.Property.Tree.RegisterPrefabDictionaryAddKeyModification(parentProperty, index, newKey);
                    }

                    //
                    // Changing just one key may have changed the entire ordering of the dictionary.
                    // Keep everything valid by refreshing the names and paths of every single child
                    // property of the dictionary.
                    //

                    handler.ForceUpdate();
                    parentProperty.Children.ClearPathCache();
                    parentProperty.Children.Update();

                    for (int i = 0; i < parentProperty.Children.Count; i++)
                    {
                        parentProperty.Children[i].ForceUpdatePropertyNameAndPath(i);
                    }

                    //
                    // Get the value entry which now represents the new key, and register a value
                    // modification for it immediately, so as not to lose the old value.
                    //

                    if (isPrefab)
                    {
                        string childName = DictionaryKeyUtility.GetDictionaryKeyString(newKey);

                        var child = parentProperty.Children[childName];
                        child.ValueEntry.Update();
                        child = child.Children["Value"];
                        child.ValueEntry.Update();

                        if (handler.SupportsPrefabModifications)
                        {
                            this.Property.Tree.RegisterPrefabValueModification(child, index, forceImmediate: true);
                        }
                    }
                }
            }
            else if (!PropertyValueEntry <TValue> .EqualityComparer(oldValue, newValue))
            {
                // Only value has changed, this is much simpler
                dict[newKey] = newValue;
            }
        }
        private ValueSetter <TDictionary, EditableKeyValuePair <TKey, TValue> > CreateSetter(int childIndex)
        {
            return((ref TDictionary dict, EditableKeyValuePair <TKey, TValue> value) =>
            {
                this.EnsureUpdated();

                var keys = this.keys[this.dictIndexMap[dict]];

                if (childIndex >= keys.Count)
                {
                    this.Update();
                    keys = this.keys[this.dictIndexMap[dict]];
                }

                TKey oldKey = keys[childIndex];
                TValue oldValue;

                dict.TryGetValue(oldKey, out oldValue);

                TKey newKey = value.Key;
                TValue newValue = value.Value;

                bool keysAreEqual = PropertyValueEntry <TKey> .EqualityComparer(oldKey, newKey);

                if (!keysAreEqual)
                {
                    // Key has changed
                    if (dict.ContainsKey(newKey))
                    {
                        // Ignore if new key already exists in dictionary
                        // and assign a temporary invalid key
                        this.tempKeys[childIndex] = new TempKeyInfo()
                        {
                            Key = newKey, IsInvalid = true
                        };
                    }
                    else if (!this.ValueApplyIsTemporary)
                    {
                        bool isPrefab = this.Property.SupportsPrefabModifications;

                        this.tempKeys.Remove(childIndex);

                        dict.Remove(oldKey);
                        dict.Add(newKey, newValue);

                        if (isPrefab)
                        {
                            for (int i = 0; i < this.Property.Tree.WeakTargets.Count; i++)
                            {
                                this.Property.Tree.PrefabModificationHandler.RegisterPrefabDictionaryRemoveKeyModification(this.Property, i, oldKey);
                                this.Property.Tree.PrefabModificationHandler.RegisterPrefabDictionaryAddKeyModification(this.Property, i, newKey);
                            }
                        }

                        //
                        // Changing just one key may have changed the entire ordering of the dictionary.
                        // Keep everything valid by refreshing all properties.
                        //
                        this.childInfos.Clear();
                        this.Property.Children.ClearAndDisposeChildren();

                        //
                        // Get the value entry which now represents the new key, and register a value
                        // modification for it immediately, so as not to lose the old value.
                        //
                        // ( Calling update with a new value compared to the prefab registers the
                        //   appropriate value modifications immediately )
                        //

                        if (isPrefab)
                        {
                            this.Update();

                            string keyStr = DictionaryKeyUtility.GetDictionaryKeyString(newKey);
                            var keyEntry = this.Property.Children[keyStr];
                            keyEntry.Update(true);

                            foreach (var child in keyEntry.Children.Recurse())
                            {
                                child.Update(true);
                            }
                        }
                    }
                    else
                    {
                        this.tempKeys[childIndex] = new TempKeyInfo()
                        {
                            Key = newKey, IsInvalid = false
                        };
                    }
                }
                else if (!PropertyValueEntry <TValue> .EqualityComparer(oldValue, newValue))
                {
                    // Only value has changed, this is much simpler
                    dict[newKey] = newValue;
                }

                if (value.IsTempKey && keysAreEqual)
                {
                    // The temp key set has set the same key back, so it's not invalid any more; it was cancelled
                    this.tempKeys.Remove(childIndex);
                }
            });
        }
예제 #5
0
 /// <summary>
 /// Not yet documented.
 /// </summary>
 public bool Equals(EditableKeyValuePair <TKey, TValue> other)
 {
     // We consider these to be equal if only the key is equal
     return(PropertyValueEntry <TKey> .EqualityComparer(this.Key, other.Key));
 }