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