CnC_Remastered_Collection

Command and Conquer: Red Alert
Log | Files | Refs | README | LICENSE

PropertyTracker.cs (6820B)


      1 //
      2 // Copyright 2020 Electronic Arts Inc.
      3 //
      4 // The Command & Conquer Map Editor and corresponding source code is free 
      5 // software: you can redistribute it and/or modify it under the terms of 
      6 // the GNU General Public License as published by the Free Software Foundation, 
      7 // either version 3 of the License, or (at your option) any later version.
      8 
      9 // The Command & Conquer Map Editor and corresponding source code is distributed 
     10 // in the hope that it will be useful, but with permitted additional restrictions 
     11 // under Section 7 of the GPL. See the GNU General Public License in LICENSE.TXT 
     12 // distributed with this program. You should have received a copy of the 
     13 // GNU General Public License along with permitted additional restrictions 
     14 // with this program. If not, see https://github.com/electronicarts/CnC_Remastered_Collection
     15 using System;
     16 using System.Collections.Generic;
     17 using System.ComponentModel;
     18 using System.Dynamic;
     19 using System.Linq;
     20 using System.Reflection;
     21 
     22 namespace MobiusEditor.Utility
     23 {
     24     public class TrackablePropertyDescriptor<T> : PropertyDescriptor
     25     {
     26         private readonly T obj;
     27         private readonly PropertyInfo propertyInfo;
     28         private readonly Dictionary<string, object> propertyValues;
     29 
     30         public override Type ComponentType => obj.GetType();
     31 
     32         public override bool IsReadOnly => false;
     33 
     34         public override Type PropertyType => propertyInfo.PropertyType;
     35 
     36         public TrackablePropertyDescriptor(string name, T obj, PropertyInfo propertyInfo, Dictionary<string, object> propertyValues)
     37             : base(name, null)
     38         {
     39             this.obj = obj;
     40             this.propertyInfo = propertyInfo;
     41             this.propertyValues = propertyValues;
     42         }
     43 
     44         public override bool CanResetValue(object component)
     45         {
     46             return propertyValues.ContainsKey(Name);
     47         }
     48 
     49         public override object GetValue(object component)
     50         {
     51             if (propertyValues.TryGetValue(Name, out object result))
     52             {
     53                 return result;
     54             }
     55             return propertyInfo.GetValue(obj);
     56         }
     57 
     58         public override void ResetValue(object component)
     59         {
     60             propertyValues.Remove(Name);
     61         }
     62 
     63         public override void SetValue(object component, object value)
     64         {
     65             if (Equals(propertyInfo.GetValue(obj), value))
     66             {
     67                 propertyValues.Remove(Name);
     68             }
     69             else
     70             {
     71                 propertyValues[Name] = value;
     72             }
     73         }
     74 
     75         public override bool ShouldSerializeValue(object component)
     76         {
     77             return false;
     78         }
     79     }
     80 
     81     public class PropertyTracker<T> : DynamicObject, ICustomTypeDescriptor
     82     {
     83         private readonly Dictionary<string, PropertyInfo> trackableProperties;
     84         private readonly Dictionary<string, object> propertyValues = new Dictionary<string, object>();
     85 
     86         public T Object { get; private set; }
     87         
     88         public PropertyTracker(T obj)
     89         {
     90             Object = obj;
     91 
     92             trackableProperties = Object.GetType()
     93                 .GetProperties(BindingFlags.Public | BindingFlags.Instance)
     94                 .Where(p => (p.GetGetMethod() != null) && (p.GetSetMethod() != null))
     95                 .ToDictionary(k => k.Name, v => v);
     96         }
     97 
     98         public void Revert() => propertyValues.Clear();
     99 
    100         public void Commit()
    101         {
    102             foreach (var propertyValue in propertyValues)
    103             {
    104                 trackableProperties[propertyValue.Key].SetValue(Object, propertyValue.Value);
    105             }
    106             propertyValues.Clear();
    107         }
    108 
    109         public IDictionary<string, object> GetUndoValues() => propertyValues.ToDictionary(kv => kv.Key, kv => trackableProperties[kv.Key].GetValue(Object));
    110 
    111         public IDictionary<string, object> GetRedoValues() => new Dictionary<string, object>(propertyValues);
    112 
    113         public override bool TryGetMember(GetMemberBinder binder, out object result)
    114         {
    115             if (!trackableProperties.TryGetValue(binder.Name, out PropertyInfo property))
    116             {
    117                 result = null;
    118                 return false;
    119             }
    120 
    121             if (!propertyValues.TryGetValue(binder.Name, out result))
    122             {
    123                 result = property.GetValue(Object);
    124             }
    125             return true;
    126         }
    127 
    128         public override bool TrySetMember(SetMemberBinder binder, object value)
    129         {
    130             if (!trackableProperties.TryGetValue(binder.Name, out PropertyInfo property))
    131             {
    132                 return false;
    133             }
    134 
    135             if (Equals(property.GetValue(Object), value))
    136             {
    137                 propertyValues.Remove(binder.Name);
    138             }
    139             else
    140             {
    141                 propertyValues[binder.Name] = value;
    142             }
    143             return true;
    144         }
    145 
    146         public AttributeCollection GetAttributes()
    147         {
    148             return TypeDescriptor.GetAttributes(Object.GetType());
    149         }
    150 
    151         public string GetClassName()
    152         {
    153             return TypeDescriptor.GetClassName(Object.GetType());
    154         }
    155 
    156         public string GetComponentName()
    157         {
    158             return TypeDescriptor.GetComponentName(Object.GetType());
    159         }
    160 
    161         public TypeConverter GetConverter()
    162         {
    163             return TypeDescriptor.GetConverter(Object.GetType());
    164         }
    165 
    166         public EventDescriptor GetDefaultEvent()
    167         {
    168             return TypeDescriptor.GetDefaultEvent(Object.GetType());
    169         }
    170 
    171         public PropertyDescriptor GetDefaultProperty()
    172         {
    173             return TypeDescriptor.GetDefaultProperty(Object.GetType());
    174         }
    175 
    176         public object GetEditor(Type editorBaseType)
    177         {
    178             return TypeDescriptor.GetEditor(Object.GetType(), editorBaseType);
    179         }
    180 
    181         public EventDescriptorCollection GetEvents()
    182         {
    183             return TypeDescriptor.GetEvents(Object.GetType());
    184         }
    185 
    186         public EventDescriptorCollection GetEvents(Attribute[] attributes)
    187         {
    188             return TypeDescriptor.GetEvents(Object.GetType(), attributes);
    189         }
    190 
    191         public PropertyDescriptorCollection GetProperties()
    192         {
    193             var propertyDescriptors = trackableProperties.Select(kv =>
    194             {
    195                 return new TrackablePropertyDescriptor<T>(kv.Key, Object, kv.Value, propertyValues);
    196             }).ToArray();
    197             return new PropertyDescriptorCollection(propertyDescriptors);
    198         }
    199 
    200         public PropertyDescriptorCollection GetProperties(Attribute[] attributes)
    201         {
    202             return GetProperties();
    203         }
    204 
    205         public object GetPropertyOwner(PropertyDescriptor pd)
    206         {
    207             return Object;
    208         }
    209     }
    210 }