diff --git a/src/Artemis.Core/Artemis.Core.csproj.DotSettings b/src/Artemis.Core/Artemis.Core.csproj.DotSettings index 461cc1c15..261d8170b 100644 --- a/src/Artemis.Core/Artemis.Core.csproj.DotSettings +++ b/src/Artemis.Core/Artemis.Core.csproj.DotSettings @@ -57,6 +57,7 @@ True True True + True True True True diff --git a/src/Artemis.Core/Events/DataModelPathEventArgs.cs b/src/Artemis.Core/Events/DataModelPathEventArgs.cs new file mode 100644 index 000000000..6e3da98ed --- /dev/null +++ b/src/Artemis.Core/Events/DataModelPathEventArgs.cs @@ -0,0 +1,20 @@ +using System; + +namespace Artemis.Core +{ + /// + /// Provides data about data model path related events + /// + public class DataModelPathEventArgs : EventArgs + { + internal DataModelPathEventArgs(DataModelPath dataModelPath) + { + DataModelPath = dataModelPath; + } + + /// + /// Gets the data model path this event is related to + /// + public DataModelPath DataModelPath { get; } + } +} \ No newline at end of file diff --git a/src/Artemis.Core/Events/DynamicDataModelChildEventArgs.cs b/src/Artemis.Core/Events/DynamicDataModelChildEventArgs.cs index 9248a716a..030fd815e 100644 --- a/src/Artemis.Core/Events/DynamicDataModelChildEventArgs.cs +++ b/src/Artemis.Core/Events/DynamicDataModelChildEventArgs.cs @@ -1,5 +1,5 @@ using System; -using Artemis.Core.DataModelExpansions; +using Artemis.Core.Modules; namespace Artemis.Core { diff --git a/src/Artemis.Core/Models/Profile/Conditions/Wrappers/EventPredicateWrapperDataModel.cs b/src/Artemis.Core/Models/Profile/Conditions/Wrappers/EventPredicateWrapperDataModel.cs index 76e19f3c4..7b30c20f9 100644 --- a/src/Artemis.Core/Models/Profile/Conditions/Wrappers/EventPredicateWrapperDataModel.cs +++ b/src/Artemis.Core/Models/Profile/Conditions/Wrappers/EventPredicateWrapperDataModel.cs @@ -1,5 +1,5 @@ using System; -using Artemis.Core.DataModelExpansions; +using Artemis.Core.Modules; namespace Artemis.Core { diff --git a/src/Artemis.Core/Models/Profile/Conditions/Wrappers/ListPredicateWrapperDataModel.cs b/src/Artemis.Core/Models/Profile/Conditions/Wrappers/ListPredicateWrapperDataModel.cs index f6eafa524..05b3e598e 100644 --- a/src/Artemis.Core/Models/Profile/Conditions/Wrappers/ListPredicateWrapperDataModel.cs +++ b/src/Artemis.Core/Models/Profile/Conditions/Wrappers/ListPredicateWrapperDataModel.cs @@ -1,5 +1,5 @@ using System; -using Artemis.Core.DataModelExpansions; +using Artemis.Core.Modules; namespace Artemis.Core { diff --git a/src/Artemis.Core/Models/Profile/DataBindings/IDataBinding.cs b/src/Artemis.Core/Models/Profile/DataBindings/IDataBinding.cs index c2913c85f..1f54ca146 100644 --- a/src/Artemis.Core/Models/Profile/DataBindings/IDataBinding.cs +++ b/src/Artemis.Core/Models/Profile/DataBindings/IDataBinding.cs @@ -1,5 +1,5 @@ using System; -using Artemis.Core.DataModelExpansions; +using Artemis.Core.Modules; namespace Artemis.Core { diff --git a/src/Artemis.Core/Models/Profile/DataModel/DataModelEvent.cs b/src/Artemis.Core/Models/Profile/DataModel/DataModelEvent.cs index cd56a38b2..352c3c09b 100644 --- a/src/Artemis.Core/Models/Profile/DataModel/DataModelEvent.cs +++ b/src/Artemis.Core/Models/Profile/DataModel/DataModelEvent.cs @@ -1,7 +1,7 @@ using System; using System.Collections.Generic; using System.Linq; -using Artemis.Core.DataModelExpansions; +using Artemis.Core.Modules; namespace Artemis.Core { diff --git a/src/Artemis.Core/Models/Profile/DataModel/DataModelEventArgs.cs b/src/Artemis.Core/Models/Profile/DataModel/DataModelEventArgs.cs index 4a0431155..edd41bb6a 100644 --- a/src/Artemis.Core/Models/Profile/DataModel/DataModelEventArgs.cs +++ b/src/Artemis.Core/Models/Profile/DataModel/DataModelEventArgs.cs @@ -1,5 +1,5 @@ using System; -using Artemis.Core.DataModelExpansions; +using Artemis.Core.Modules; namespace Artemis.Core { diff --git a/src/Artemis.Core/Models/Profile/DataModel/DataModelPath.cs b/src/Artemis.Core/Models/Profile/DataModel/DataModelPath.cs index c2eb9f1e2..baa7eac6c 100644 --- a/src/Artemis.Core/Models/Profile/DataModel/DataModelPath.cs +++ b/src/Artemis.Core/Models/Profile/DataModel/DataModelPath.cs @@ -3,7 +3,7 @@ using System.Collections.Generic; using System.Linq; using System.Linq.Expressions; using System.Reflection; -using Artemis.Core.DataModelExpansions; +using Artemis.Core.Modules; using Artemis.Storage.Entities.Profile; namespace Artemis.Core @@ -175,6 +175,8 @@ namespace Artemis.Core internal void Invalidate() { + Target?.RemoveDataModelPath(this); + foreach (DataModelPathSegment dataModelPathSegment in _segments) dataModelPathSegment.Dispose(); _segments.Clear(); @@ -187,11 +189,11 @@ namespace Artemis.Core internal void Initialize() { - Invalidate(); - if (Target == null) return; + Target.AddDataModelPath(this); + DataModelPathSegment startSegment = new(this, "target", "target"); startSegment.Node = _segments.AddFirst(startSegment); @@ -260,7 +262,7 @@ namespace Artemis.Core DataModelStore.DataModelAdded += DataModelStoreOnDataModelAdded; DataModelStore.DataModelRemoved += DataModelStoreOnDataModelRemoved; } - + #region IDisposable /// @@ -330,6 +332,7 @@ namespace Artemis.Core if (e.Registration.DataModel.Module.Id != Entity.DataModelId) return; + Invalidate(); Target = e.Registration.DataModel; Initialize(); } @@ -339,8 +342,8 @@ namespace Artemis.Core if (e.Registration.DataModel.Module.Id != Entity.DataModelId) return; - Target = null; Invalidate(); + Target = null; } #endregion diff --git a/src/Artemis.Core/Models/Profile/DataModel/DataModelPathSegment.cs b/src/Artemis.Core/Models/Profile/DataModel/DataModelPathSegment.cs index 7531cb09f..9e5be4a9e 100644 --- a/src/Artemis.Core/Models/Profile/DataModel/DataModelPathSegment.cs +++ b/src/Artemis.Core/Models/Profile/DataModel/DataModelPathSegment.cs @@ -3,7 +3,7 @@ using System.Collections.Generic; using System.Linq; using System.Linq.Expressions; using System.Reflection; -using Artemis.Core.DataModelExpansions; +using Artemis.Core.Modules; using Humanizer; namespace Artemis.Core @@ -301,7 +301,7 @@ namespace Artemis.Core private void DynamicChildOnDynamicChildRemoved(object? sender, DynamicDataModelChildEventArgs e) { if (e.DynamicChild.BaseValue == _dynamicDataModel) - DataModelPath.Initialize(); + DataModelPath.Invalidate(); } #endregion diff --git a/src/Artemis.Core/Models/Profile/DataModel/ValueChangedEvent/DataModelValueChangedEventArgs.cs b/src/Artemis.Core/Models/Profile/DataModel/ValueChangedEvent/DataModelValueChangedEventArgs.cs index f82169770..b25976a61 100644 --- a/src/Artemis.Core/Models/Profile/DataModel/ValueChangedEvent/DataModelValueChangedEventArgs.cs +++ b/src/Artemis.Core/Models/Profile/DataModel/ValueChangedEvent/DataModelValueChangedEventArgs.cs @@ -1,4 +1,4 @@ -using Artemis.Core.DataModelExpansions; +using Artemis.Core.Modules; namespace Artemis.Core { diff --git a/src/Artemis.Core/Models/Profile/ProfileCategory.cs b/src/Artemis.Core/Models/Profile/ProfileCategory.cs index b5d0b85f2..a15a63e91 100644 --- a/src/Artemis.Core/Models/Profile/ProfileCategory.cs +++ b/src/Artemis.Core/Models/Profile/ProfileCategory.cs @@ -5,6 +5,9 @@ using Artemis.Storage.Entities.Profile; namespace Artemis.Core { + /// + /// Represents a category containing + /// public class ProfileCategory : CorePropertyChanged, IStorageModel { private readonly List _profileConfigurations = new(); diff --git a/src/Artemis.Core/Models/Profile/RenderProfileElement.cs b/src/Artemis.Core/Models/Profile/RenderProfileElement.cs index 559feecdc..c63bbedef 100644 --- a/src/Artemis.Core/Models/Profile/RenderProfileElement.cs +++ b/src/Artemis.Core/Models/Profile/RenderProfileElement.cs @@ -59,6 +59,8 @@ namespace Artemis.Core foreach (BaseLayerEffect baseLayerEffect in LayerEffects) baseLayerEffect.Dispose(); + DisplayCondition?.Dispose(); + base.Dispose(disposing); } diff --git a/src/Artemis.Core/Models/ProfileConfiguration/ProfileConfiguration.cs b/src/Artemis.Core/Models/ProfileConfiguration/ProfileConfiguration.cs index 01d7ef2dd..f70ef6e9c 100644 --- a/src/Artemis.Core/Models/ProfileConfiguration/ProfileConfiguration.cs +++ b/src/Artemis.Core/Models/ProfileConfiguration/ProfileConfiguration.cs @@ -1,13 +1,18 @@ -using System.Collections.Generic; +using System; +using System.Collections.Generic; using System.Linq; using Artemis.Core.Modules; using Artemis.Storage.Entities.Profile; namespace Artemis.Core { - public class ProfileConfiguration : CorePropertyChanged, IStorageModel + /// + /// Represents the configuration of a profile, contained in a + /// + public class ProfileConfiguration : CorePropertyChanged, IStorageModel, IDisposable { private ProfileCategory _category; + private bool _disposed; private bool _isMissingModule; private bool _isSuspended; @@ -140,11 +145,17 @@ namespace Artemis.Core /// public void Update() { + if (_disposed) + throw new ObjectDisposedException("ProfileConfiguration"); + ActivationConditionMet = ActivationCondition == null || ActivationCondition.Evaluate(); } public bool ShouldBeActive(bool includeActivationCondition) { + if (_disposed) + throw new ObjectDisposedException("ProfileConfiguration"); + if (Category.IsSuspended || IsSuspended || IsMissingModule) return false; @@ -161,15 +172,32 @@ namespace Artemis.Core internal void LoadModules(List enabledModules) { + if (_disposed) + throw new ObjectDisposedException("ProfileConfiguration"); + Module = enabledModules.FirstOrDefault(m => m.Id == Entity.ModuleId); IsMissingModule = Module == null && Entity.ModuleId != null; } + #region IDisposable + + /// + public void Dispose() + { + _disposed = true; + ActivationCondition?.Dispose(); + } + + #endregion + #region Implementation of IStorageModel /// public void Load() { + if (_disposed) + throw new ObjectDisposedException("ProfileConfiguration"); + Name = Entity.Name; IsSuspended = Entity.IsSuspended; ActivationBehaviour = (ActivationBehaviour) Entity.ActivationBehaviour; @@ -185,6 +213,9 @@ namespace Artemis.Core /// public void Save() { + if (_disposed) + throw new ObjectDisposedException("ProfileConfiguration"); + Entity.Name = Name; Entity.IsSuspended = IsSuspended; Entity.ActivationBehaviour = (int) ActivationBehaviour; @@ -199,9 +230,7 @@ namespace Artemis.Core Entity.ActivationCondition = ActivationCondition.Entity; } else - { Entity.ActivationCondition = null; - } if (!IsMissingModule) Entity.ModuleId = Module?.Id; diff --git a/src/Artemis.Core/Plugins/Modules/Attributes/DataModelIgnoreAttribute.cs b/src/Artemis.Core/Plugins/Modules/Attributes/DataModelIgnoreAttribute.cs index a9339b2ee..6f3d06387 100644 --- a/src/Artemis.Core/Plugins/Modules/Attributes/DataModelIgnoreAttribute.cs +++ b/src/Artemis.Core/Plugins/Modules/Attributes/DataModelIgnoreAttribute.cs @@ -1,6 +1,6 @@ using System; -namespace Artemis.Core.DataModelExpansions +namespace Artemis.Core.Modules { /// /// Represents an attribute that marks a data model property to be ignored by the UI diff --git a/src/Artemis.Core/Plugins/Modules/Attributes/DataModelProperty.cs b/src/Artemis.Core/Plugins/Modules/Attributes/DataModelProperty.cs index 3f6ee745a..11fe2993f 100644 --- a/src/Artemis.Core/Plugins/Modules/Attributes/DataModelProperty.cs +++ b/src/Artemis.Core/Plugins/Modules/Attributes/DataModelProperty.cs @@ -1,6 +1,6 @@ using System; -namespace Artemis.Core.DataModelExpansions +namespace Artemis.Core.Modules { /// /// Represents an attribute that describes a data model property diff --git a/src/Artemis.Core/Plugins/Modules/DataModel.cs b/src/Artemis.Core/Plugins/Modules/DataModel.cs index 57bd563bd..b4c89b08b 100644 --- a/src/Artemis.Core/Plugins/Modules/DataModel.cs +++ b/src/Artemis.Core/Plugins/Modules/DataModel.cs @@ -6,15 +6,15 @@ using System.Linq; using System.Reflection; using Humanizer; using Newtonsoft.Json; -using Module = Artemis.Core.Modules.Module; -namespace Artemis.Core.DataModelExpansions +namespace Artemis.Core.Modules { /// /// Represents a data model that contains information on a game/application etc. /// public abstract class DataModel { + private readonly HashSet _activePathsHashSet = new(); private readonly List _activePaths = new(); private readonly Dictionary _dynamicChildren = new(); @@ -65,36 +65,7 @@ namespace Artemis.Core.DataModelExpansions /// public ReadOnlyCollection GetHiddenProperties() { - if (Module is Module module) - return module.HiddenProperties; - - return new List().AsReadOnly(); - } - - /// - /// Occurs when a dynamic child has been added to this data model - /// - public event EventHandler? DynamicChildAdded; - - /// - /// Occurs when a dynamic child has been removed from this data model - /// - public event EventHandler? DynamicChildRemoved; - - /// - /// Invokes the event - /// - protected virtual void OnDynamicDataModelAdded(DynamicDataModelChildEventArgs e) - { - DynamicChildAdded?.Invoke(this, e); - } - - /// - /// Invokes the event - /// - protected virtual void OnDynamicDataModelRemoved(DynamicDataModelChildEventArgs e) - { - DynamicChildRemoved?.Invoke(this, e); + return Module.HiddenProperties; } #region Dynamic children @@ -285,15 +256,103 @@ namespace Artemis.Core.DataModelExpansions #region Paths + /// + /// Determines whether the provided dot-separated path is in use + /// + /// The path to check per example: MyDataModelChild.MyDataModelProperty + /// + /// If any child of the given path will return true as well; if + /// only an exact path match returns . + /// + internal bool IsPropertyInUse(string path, bool includeChildren) + { + path = path.ToUpperInvariant(); + return includeChildren + ? _activePathsHashSet.Any(p => p.StartsWith(path, StringComparison.Ordinal)) + : _activePathsHashSet.Contains(path); + } + internal void AddDataModelPath(DataModelPath path) { - if (!_activePaths.Contains(path)) - _activePaths.Add(path); + if (_activePaths.Contains(path)) + return; + + _activePaths.Add(path); + + // Add to the hashset if this is the first path pointing + string hashPath = path.Path.ToUpperInvariant(); + if (!_activePathsHashSet.Contains(hashPath)) + _activePathsHashSet.Add(hashPath); + + OnActivePathAdded(new DataModelPathEventArgs(path)); } internal void RemoveDataModelPath(DataModelPath path) { - _activePaths.Remove(path); + if (!_activePaths.Remove(path)) + return; + + // Remove from the hashset if this was the last path pointing there + if (_activePaths.All(p => p.Path != path.Path)) + _activePathsHashSet.Remove(path.Path.ToUpperInvariant()); + + OnActivePathRemoved(new DataModelPathEventArgs(path)); + } + + #endregion + + #region Events + + /// + /// Occurs when a dynamic child has been added to this data model + /// + public event EventHandler? DynamicChildAdded; + + /// + /// Occurs when a dynamic child has been removed from this data model + /// + public event EventHandler? DynamicChildRemoved; + + /// + /// Occurs when a dynamic child has been added to this data model + /// + public event EventHandler? ActivePathAdded; + + /// + /// Occurs when a dynamic child has been removed from this data model + /// + public event EventHandler? ActivePathRemoved; + + /// + /// Invokes the event + /// + protected virtual void OnDynamicDataModelAdded(DynamicDataModelChildEventArgs e) + { + DynamicChildAdded?.Invoke(this, e); + } + + /// + /// Invokes the event + /// + protected virtual void OnDynamicDataModelRemoved(DynamicDataModelChildEventArgs e) + { + DynamicChildRemoved?.Invoke(this, e); + } + + /// + /// Invokes the event + /// + protected virtual void OnActivePathAdded(DataModelPathEventArgs e) + { + ActivePathAdded?.Invoke(this, e); + } + + /// + /// Invokes the event + /// + protected virtual void OnActivePathRemoved(DataModelPathEventArgs e) + { + ActivePathRemoved?.Invoke(this, e); } #endregion diff --git a/src/Artemis.Core/Plugins/Modules/DynamicChild.cs b/src/Artemis.Core/Plugins/Modules/DynamicChild.cs index 5e5732b55..203562865 100644 --- a/src/Artemis.Core/Plugins/Modules/DynamicChild.cs +++ b/src/Artemis.Core/Plugins/Modules/DynamicChild.cs @@ -1,6 +1,6 @@ using System; -namespace Artemis.Core.DataModelExpansions +namespace Artemis.Core.Modules { /// /// Represents a dynamic child value with its property attribute diff --git a/src/Artemis.Core/Plugins/Modules/Module.cs b/src/Artemis.Core/Plugins/Modules/Module.cs index edf3cb340..aa2d84691 100644 --- a/src/Artemis.Core/Plugins/Modules/Module.cs +++ b/src/Artemis.Core/Plugins/Modules/Module.cs @@ -5,7 +5,7 @@ using System.IO; using System.Linq; using System.Linq.Expressions; using System.Reflection; -using Artemis.Core.DataModelExpansions; +using System.Text; namespace Artemis.Core.Modules { @@ -25,7 +25,8 @@ namespace Artemis.Core.Modules } /// - /// Hide the provided property using a lambda expression, e.g. HideProperty(dm => dm.TimeDataModel.CurrentTimeUTC) + /// Hide the provided property using a lambda expression, e.g. + /// HideProperty(dm => dm.TimeDataModel.CurrentTimeUTC) /// /// A lambda expression pointing to the property to ignore public void HideProperty(Expression> propertyLambda) @@ -36,8 +37,8 @@ namespace Artemis.Core.Modules } /// - /// Stop hiding the provided property using a lambda expression, e.g. ShowProperty(dm => - /// dm.TimeDataModel.CurrentTimeUTC) + /// Stop hiding the provided property using a lambda expression, e.g. + /// ShowProperty(dm => dm.TimeDataModel.CurrentTimeUTC) /// /// A lambda expression pointing to the property to stop ignoring public void ShowProperty(Expression> propertyLambda) @@ -46,6 +47,36 @@ namespace Artemis.Core.Modules HiddenPropertiesList.RemoveAll(p => p.Equals(propertyInfo)); } + /// + /// Determines whether the provided dot-separated path is actively being used by Artemis + /// Note: is slightly faster but string-based. + /// + /// + /// The path to check per example: IsPropertyInUse(dm => dm.TimeDataModel.CurrentTimeUTC) + /// + /// + /// If any child of the given path will return true as well; if + /// only an exact path match returns . + /// + public bool IsPropertyInUse(Expression> propertyLambda, bool includeChildren) + { + string path = GetMemberPath((MemberExpression) propertyLambda.Body); + return IsPropertyInUse(path, includeChildren); + } + + /// + /// Determines whether the provided dot-separated path is actively being used by Artemis + /// + /// The path to check per example: MyDataModelChild.MyDataModelProperty + /// + /// If any child of the given path will return true as well; if + /// only an exact path match returns . + /// + public bool IsPropertyInUse(string path, bool includeChildren) + { + return DataModel.IsPropertyInUse(path, includeChildren); + } + internal override void InternalEnable() { DataModel = Activator.CreateInstance(); @@ -59,6 +90,20 @@ namespace Artemis.Core.Modules Deactivate(true); base.InternalDisable(); } + + private static string GetMemberPath(MemberExpression? me) + { + StringBuilder builder = new(); + while (me != null) + { + builder.Insert(0, me.Member.Name); + me = me.Expression as MemberExpression; + if (me != null) + builder.Insert(0, "."); + } + + return builder.ToString(); + } } /// @@ -78,7 +123,7 @@ namespace Artemis.Core.Modules /// Gets a read only collection of default profile paths /// public IReadOnlyCollection<(DefaultCategoryName, string)> DefaultProfilePaths => _defaultProfilePaths.AsReadOnly(); - + /// /// A list of activation requirements /// diff --git a/src/Artemis.Core/Services/CoreService.cs b/src/Artemis.Core/Services/CoreService.cs index f9e64e00f..f2a279a6f 100644 --- a/src/Artemis.Core/Services/CoreService.cs +++ b/src/Artemis.Core/Services/CoreService.cs @@ -4,7 +4,6 @@ using System.Diagnostics; using System.Linq; using System.Reflection; using System.Threading.Tasks; -using Artemis.Core.DataModelExpansions; using Artemis.Core.Ninject; using Artemis.Storage; using HidSharp; diff --git a/src/Artemis.Core/Services/Registration/DataModelService.cs b/src/Artemis.Core/Services/Registration/DataModelService.cs index 90e1c4739..450d2f239 100644 --- a/src/Artemis.Core/Services/Registration/DataModelService.cs +++ b/src/Artemis.Core/Services/Registration/DataModelService.cs @@ -1,7 +1,6 @@ using System; using System.Collections.Generic; using System.Linq; -using Artemis.Core.DataModelExpansions; using Artemis.Core.Modules; namespace Artemis.Core.Services diff --git a/src/Artemis.Core/Services/Registration/Interfaces/IDataModelService.cs b/src/Artemis.Core/Services/Registration/Interfaces/IDataModelService.cs index 072c68601..9d5b390fc 100644 --- a/src/Artemis.Core/Services/Registration/Interfaces/IDataModelService.cs +++ b/src/Artemis.Core/Services/Registration/Interfaces/IDataModelService.cs @@ -1,6 +1,6 @@ using System; using System.Collections.Generic; -using Artemis.Core.DataModelExpansions; +using Artemis.Core.Modules; namespace Artemis.Core.Services { diff --git a/src/Artemis.Core/Services/Storage/ProfileService.cs b/src/Artemis.Core/Services/Storage/ProfileService.cs index 41efce23d..b3fb0c267 100644 --- a/src/Artemis.Core/Services/Storage/ProfileService.cs +++ b/src/Artemis.Core/Services/Storage/ProfileService.cs @@ -357,6 +357,8 @@ namespace Artemis.Core.Services ProfileEntity profileEntity = _profileRepository.Get(profileConfiguration.Entity.ProfileId); if (profileEntity != null) _profileRepository.Remove(profileEntity); + + profileConfiguration.Dispose(); } public void SaveProfileCategory(ProfileCategory profileCategory) diff --git a/src/Artemis.Core/Services/WebServer/EndPoints/DataModelJsonPluginEndPoint.cs b/src/Artemis.Core/Services/WebServer/EndPoints/DataModelJsonPluginEndPoint.cs index d0e5e206b..70a019331 100644 --- a/src/Artemis.Core/Services/WebServer/EndPoints/DataModelJsonPluginEndPoint.cs +++ b/src/Artemis.Core/Services/WebServer/EndPoints/DataModelJsonPluginEndPoint.cs @@ -1,7 +1,6 @@ using System; using System.IO; using System.Threading.Tasks; -using Artemis.Core.DataModelExpansions; using Artemis.Core.Modules; using EmbedIO; using Newtonsoft.Json; diff --git a/src/Artemis.Core/Services/WebServer/Interfaces/IWebServerService.cs b/src/Artemis.Core/Services/WebServer/Interfaces/IWebServerService.cs index 22051d7fd..7c8e2124f 100644 --- a/src/Artemis.Core/Services/WebServer/Interfaces/IWebServerService.cs +++ b/src/Artemis.Core/Services/WebServer/Interfaces/IWebServerService.cs @@ -1,6 +1,5 @@ using System; using System.Threading.Tasks; -using Artemis.Core.DataModelExpansions; using Artemis.Core.Modules; using EmbedIO; using EmbedIO.WebApi; diff --git a/src/Artemis.Core/Services/WebServer/WebServerService.cs b/src/Artemis.Core/Services/WebServer/WebServerService.cs index 4c9272d91..0d7654812 100644 --- a/src/Artemis.Core/Services/WebServer/WebServerService.cs +++ b/src/Artemis.Core/Services/WebServer/WebServerService.cs @@ -4,7 +4,6 @@ using System.IO; using System.Linq; using System.Text; using System.Threading.Tasks; -using Artemis.Core.DataModelExpansions; using Artemis.Core.Modules; using EmbedIO; using EmbedIO.WebApi; diff --git a/src/Artemis.Core/Stores/DataModelStore.cs b/src/Artemis.Core/Stores/DataModelStore.cs index 336dac6f5..160aed9c2 100644 --- a/src/Artemis.Core/Stores/DataModelStore.cs +++ b/src/Artemis.Core/Stores/DataModelStore.cs @@ -1,7 +1,7 @@ using System; using System.Collections.Generic; using System.Linq; -using Artemis.Core.DataModelExpansions; +using Artemis.Core.Modules; namespace Artemis.Core { diff --git a/src/Artemis.Core/Stores/Registrations/DataModelRegistration.cs b/src/Artemis.Core/Stores/Registrations/DataModelRegistration.cs index 09c162758..c1eb7f789 100644 --- a/src/Artemis.Core/Stores/Registrations/DataModelRegistration.cs +++ b/src/Artemis.Core/Stores/Registrations/DataModelRegistration.cs @@ -1,5 +1,5 @@ using System; -using Artemis.Core.DataModelExpansions; +using Artemis.Core.Modules; namespace Artemis.Core { diff --git a/src/Artemis.Core/Utilities/ExpressionUtilities.cs b/src/Artemis.Core/Utilities/ExpressionUtilities.cs index 4db041961..e460feba1 100644 --- a/src/Artemis.Core/Utilities/ExpressionUtilities.cs +++ b/src/Artemis.Core/Utilities/ExpressionUtilities.cs @@ -1,5 +1,5 @@ using System.Linq.Expressions; -using Artemis.Core.DataModelExpansions; +using Artemis.Core.Modules; namespace Artemis.Core { diff --git a/src/Artemis.UI.Shared/DataModelVisualization/DataModelDisplayViewModel.cs b/src/Artemis.UI.Shared/DataModelVisualization/DataModelDisplayViewModel.cs index 16edde678..abbc4171d 100644 --- a/src/Artemis.UI.Shared/DataModelVisualization/DataModelDisplayViewModel.cs +++ b/src/Artemis.UI.Shared/DataModelVisualization/DataModelDisplayViewModel.cs @@ -1,5 +1,5 @@ using System.Diagnostics.CodeAnalysis; -using Artemis.Core.DataModelExpansions; +using Artemis.Core.Modules; using Stylet; namespace Artemis.UI.Shared diff --git a/src/Artemis.UI.Shared/DataModelVisualization/DataModelInputViewModel.cs b/src/Artemis.UI.Shared/DataModelVisualization/DataModelInputViewModel.cs index 1c147ac43..1c9574dfb 100644 --- a/src/Artemis.UI.Shared/DataModelVisualization/DataModelInputViewModel.cs +++ b/src/Artemis.UI.Shared/DataModelVisualization/DataModelInputViewModel.cs @@ -5,7 +5,7 @@ using System.Threading.Tasks; using System.Windows; using System.Windows.Data; using System.Windows.Input; -using Artemis.Core.DataModelExpansions; +using Artemis.Core.Modules; using Stylet; namespace Artemis.UI.Shared diff --git a/src/Artemis.UI.Shared/DataModelVisualization/Input/DataModelDynamicViewModel.cs b/src/Artemis.UI.Shared/DataModelVisualization/Input/DataModelDynamicViewModel.cs index fa4ad2f99..ad6697b92 100644 --- a/src/Artemis.UI.Shared/DataModelVisualization/Input/DataModelDynamicViewModel.cs +++ b/src/Artemis.UI.Shared/DataModelVisualization/Input/DataModelDynamicViewModel.cs @@ -272,6 +272,7 @@ namespace Artemis.UI.Shared.Input _updateTimer.Dispose(); _updateTimer.Elapsed -= OnUpdateTimerOnElapsed; + DataModelViewModel?.Dispose(); DataModelPath?.Dispose(); } } diff --git a/src/Artemis.UI.Shared/DataModelVisualization/Input/DataModelStaticViewModel.cs b/src/Artemis.UI.Shared/DataModelVisualization/Input/DataModelStaticViewModel.cs index d909eb9ba..2ef06ec9a 100644 --- a/src/Artemis.UI.Shared/DataModelVisualization/Input/DataModelStaticViewModel.cs +++ b/src/Artemis.UI.Shared/DataModelVisualization/Input/DataModelStaticViewModel.cs @@ -4,7 +4,7 @@ using System.Windows; using System.Windows.Input; using System.Windows.Media; using Artemis.Core; -using Artemis.Core.DataModelExpansions; +using Artemis.Core.Modules; using Artemis.UI.Shared.Services; using MaterialDesignColors.ColorManipulation; using Stylet; diff --git a/src/Artemis.UI.Shared/DataModelVisualization/Shared/DataModelEventViewModel.cs b/src/Artemis.UI.Shared/DataModelVisualization/Shared/DataModelEventViewModel.cs index 5fab8425c..55ccdf424 100644 --- a/src/Artemis.UI.Shared/DataModelVisualization/Shared/DataModelEventViewModel.cs +++ b/src/Artemis.UI.Shared/DataModelVisualization/Shared/DataModelEventViewModel.cs @@ -1,7 +1,7 @@ using System; using System.Linq; using Artemis.Core; -using Artemis.Core.DataModelExpansions; +using Artemis.Core.Modules; using Artemis.UI.Shared.Services; namespace Artemis.UI.Shared diff --git a/src/Artemis.UI.Shared/DataModelVisualization/Shared/DataModelListViewModel.cs b/src/Artemis.UI.Shared/DataModelVisualization/Shared/DataModelListViewModel.cs index c36d7129e..09187f910 100644 --- a/src/Artemis.UI.Shared/DataModelVisualization/Shared/DataModelListViewModel.cs +++ b/src/Artemis.UI.Shared/DataModelVisualization/Shared/DataModelListViewModel.cs @@ -2,7 +2,7 @@ using System.Collections; using System.Windows.Documents; using Artemis.Core; -using Artemis.Core.DataModelExpansions; +using Artemis.Core.Modules; using Artemis.UI.Shared.Services; using Stylet; diff --git a/src/Artemis.UI.Shared/DataModelVisualization/Shared/DataModelPropertiesViewModel.cs b/src/Artemis.UI.Shared/DataModelVisualization/Shared/DataModelPropertiesViewModel.cs index 99092a24a..423af79e9 100644 --- a/src/Artemis.UI.Shared/DataModelVisualization/Shared/DataModelPropertiesViewModel.cs +++ b/src/Artemis.UI.Shared/DataModelVisualization/Shared/DataModelPropertiesViewModel.cs @@ -1,6 +1,6 @@ using System; using Artemis.Core; -using Artemis.Core.DataModelExpansions; +using Artemis.Core.Modules; using Artemis.UI.Shared.Services; namespace Artemis.UI.Shared diff --git a/src/Artemis.UI.Shared/DataModelVisualization/Shared/DataModelPropertyViewModel.cs b/src/Artemis.UI.Shared/DataModelVisualization/Shared/DataModelPropertyViewModel.cs index 3d3b20102..5f4b35891 100644 --- a/src/Artemis.UI.Shared/DataModelVisualization/Shared/DataModelPropertyViewModel.cs +++ b/src/Artemis.UI.Shared/DataModelVisualization/Shared/DataModelPropertyViewModel.cs @@ -1,6 +1,6 @@ using System; using Artemis.Core; -using Artemis.Core.DataModelExpansions; +using Artemis.Core.Modules; using Artemis.UI.Shared.Services; namespace Artemis.UI.Shared diff --git a/src/Artemis.UI.Shared/DataModelVisualization/Shared/DataModelVisualizationViewModel.cs b/src/Artemis.UI.Shared/DataModelVisualization/Shared/DataModelVisualizationViewModel.cs index 78490468a..47f3341d2 100644 --- a/src/Artemis.UI.Shared/DataModelVisualization/Shared/DataModelVisualizationViewModel.cs +++ b/src/Artemis.UI.Shared/DataModelVisualization/Shared/DataModelVisualizationViewModel.cs @@ -3,8 +3,9 @@ using System.Collections.Generic; using System.Collections.ObjectModel; using System.Linq; using System.Reflection; +using System.Text; using Artemis.Core; -using Artemis.Core.DataModelExpansions; +using Artemis.Core.Modules; using Artemis.UI.Shared.Services; using Stylet; @@ -13,7 +14,7 @@ namespace Artemis.UI.Shared /// /// Represents a base class for a view model that visualizes a part of the data model /// - public abstract class DataModelVisualizationViewModel : PropertyChangedBase + public abstract class DataModelVisualizationViewModel : PropertyChangedBase, IDisposable { private const int MaxDepth = 4; private BindableCollection _children; @@ -22,6 +23,7 @@ namespace Artemis.UI.Shared private bool _isVisualizationExpanded; private DataModelVisualizationViewModel? _parent; private DataModelPropertyAttribute? _propertyDescription; + private bool _populatedStaticChildren; internal DataModelVisualizationViewModel(DataModel? dataModel, DataModelVisualizationViewModel? parent, DataModelPath? dataModelPath) { @@ -206,21 +208,26 @@ namespace Artemis.UI.Shared if (modelType == null) throw new ArtemisSharedUIException("Failed to populate data model visualization properties, couldn't get a property type"); - // Add missing static children - foreach (PropertyInfo propertyInfo in modelType.GetProperties(BindingFlags.Public | BindingFlags.Instance).OrderBy(t => t.MetadataToken)) + // Add missing static children only once, they're static after all + if (!_populatedStaticChildren) { - string childPath = AppendToPath(propertyInfo.Name); - if (Children.Any(c => c.Path != null && c.Path.Equals(childPath))) - continue; - if (propertyInfo.GetCustomAttribute() != null) - continue; - MethodInfo? getMethod = propertyInfo.GetGetMethod(); - if (getMethod == null || getMethod.GetParameters().Any()) - continue; + foreach (PropertyInfo propertyInfo in modelType.GetProperties(BindingFlags.Public | BindingFlags.Instance).OrderBy(t => t.MetadataToken)) + { + string childPath = AppendToPath(propertyInfo.Name); + if (Children.Any(c => c.Path != null && c.Path.Equals(childPath))) + continue; + if (propertyInfo.GetCustomAttribute() != null) + continue; + MethodInfo? getMethod = propertyInfo.GetGetMethod(); + if (getMethod == null || getMethod.GetParameters().Any()) + continue; - DataModelVisualizationViewModel? child = CreateChild(dataModelUIService, childPath, GetChildDepth()); - if (child != null) - Children.Add(child); + DataModelVisualizationViewModel? child = CreateChild(dataModelUIService, childPath, GetChildDepth()); + if (child != null) + Children.Add(child); + } + + _populatedStaticChildren = true; } // Remove static children that should be hidden @@ -302,7 +309,14 @@ namespace Artemis.UI.Shared private string AppendToPath(string toAppend) { - return !string.IsNullOrEmpty(Path) ? $"{Path}.{toAppend}" : toAppend; + if (string.IsNullOrEmpty(Path)) + return toAppend; + + StringBuilder builder = new(); + builder.Append(Path); + builder.Append("."); + builder.Append(toAppend); + return builder.ToString(); } private void RequestUpdate() @@ -327,5 +341,33 @@ namespace Artemis.UI.Shared } #endregion + + #region IDisposable + + /// + /// Releases the unmanaged resources used by the object and optionally releases the managed resources. + /// + /// + /// to release both managed and unmanaged resources; + /// to release only unmanaged resources. + /// + protected virtual void Dispose(bool disposing) + { + if (disposing) + { + DataModelPath?.Dispose(); + foreach (DataModelVisualizationViewModel dataModelVisualizationViewModel in Children) + dataModelVisualizationViewModel.Dispose(true); + } + } + + /// + public void Dispose() + { + Dispose(true); + GC.SuppressFinalize(this); + } + + #endregion } } \ No newline at end of file diff --git a/src/Artemis.UI.Shared/Ninject/Factories/ISharedVMFactory.cs b/src/Artemis.UI.Shared/Ninject/Factories/ISharedVMFactory.cs index ee1c48316..21cce1e60 100644 --- a/src/Artemis.UI.Shared/Ninject/Factories/ISharedVMFactory.cs +++ b/src/Artemis.UI.Shared/Ninject/Factories/ISharedVMFactory.cs @@ -1,6 +1,5 @@ using System; using System.Collections.Generic; -using Artemis.Core.DataModelExpansions; using Artemis.Core.Modules; using Artemis.UI.Shared.Input; diff --git a/src/Artemis.UI.Shared/Services/DataModelUIService.cs b/src/Artemis.UI.Shared/Services/DataModelUIService.cs index 6066de626..dc8e5ca7e 100644 --- a/src/Artemis.UI.Shared/Services/DataModelUIService.cs +++ b/src/Artemis.UI.Shared/Services/DataModelUIService.cs @@ -2,7 +2,6 @@ using System.Collections.Generic; using System.Linq; using Artemis.Core; -using Artemis.Core.DataModelExpansions; using Artemis.Core.Modules; using Artemis.Core.Services; using Artemis.UI.Shared.DefaultTypes.DataModel.Display; diff --git a/src/Artemis.UI.Shared/Services/Interfaces/IDataModelUIService.cs b/src/Artemis.UI.Shared/Services/Interfaces/IDataModelUIService.cs index 5da6a381b..2c3f6efdb 100644 --- a/src/Artemis.UI.Shared/Services/Interfaces/IDataModelUIService.cs +++ b/src/Artemis.UI.Shared/Services/Interfaces/IDataModelUIService.cs @@ -1,7 +1,6 @@ using System; using System.Collections.Generic; using Artemis.Core; -using Artemis.Core.DataModelExpansions; using Artemis.Core.Modules; using Artemis.UI.Shared.Input; diff --git a/src/Artemis.UI/DefaultTypes/DataModel/Input/BoolDataModelInputViewModel.cs b/src/Artemis.UI/DefaultTypes/DataModel/Input/BoolDataModelInputViewModel.cs index d4f966351..8b65a2075 100644 --- a/src/Artemis.UI/DefaultTypes/DataModel/Input/BoolDataModelInputViewModel.cs +++ b/src/Artemis.UI/DefaultTypes/DataModel/Input/BoolDataModelInputViewModel.cs @@ -1,4 +1,4 @@ -using Artemis.Core.DataModelExpansions; +using Artemis.Core.Modules; using Artemis.UI.Shared; namespace Artemis.UI.DefaultTypes.DataModel.Input diff --git a/src/Artemis.UI/DefaultTypes/DataModel/Input/DoubleDataModelInputViewModel.cs b/src/Artemis.UI/DefaultTypes/DataModel/Input/DoubleDataModelInputViewModel.cs index 4fe8e02ef..a0e946d89 100644 --- a/src/Artemis.UI/DefaultTypes/DataModel/Input/DoubleDataModelInputViewModel.cs +++ b/src/Artemis.UI/DefaultTypes/DataModel/Input/DoubleDataModelInputViewModel.cs @@ -1,7 +1,7 @@ using System.Globalization; using System.Text.RegularExpressions; using System.Windows.Input; -using Artemis.Core.DataModelExpansions; +using Artemis.Core.Modules; using Artemis.UI.Shared; namespace Artemis.UI.DefaultTypes.DataModel.Input diff --git a/src/Artemis.UI/DefaultTypes/DataModel/Input/EnumDataModelInputViewModel.cs b/src/Artemis.UI/DefaultTypes/DataModel/Input/EnumDataModelInputViewModel.cs index ec374e67a..e995a49c3 100644 --- a/src/Artemis.UI/DefaultTypes/DataModel/Input/EnumDataModelInputViewModel.cs +++ b/src/Artemis.UI/DefaultTypes/DataModel/Input/EnumDataModelInputViewModel.cs @@ -1,5 +1,5 @@ using System; -using Artemis.Core.DataModelExpansions; +using Artemis.Core.Modules; using Artemis.UI.Shared; using Stylet; diff --git a/src/Artemis.UI/DefaultTypes/DataModel/Input/IntDataModelInputViewModel.cs b/src/Artemis.UI/DefaultTypes/DataModel/Input/IntDataModelInputViewModel.cs index 4a9ba6487..13faa7e2f 100644 --- a/src/Artemis.UI/DefaultTypes/DataModel/Input/IntDataModelInputViewModel.cs +++ b/src/Artemis.UI/DefaultTypes/DataModel/Input/IntDataModelInputViewModel.cs @@ -1,6 +1,6 @@ using System.Text.RegularExpressions; using System.Windows.Input; -using Artemis.Core.DataModelExpansions; +using Artemis.Core.Modules; using Artemis.UI.Shared; namespace Artemis.UI.DefaultTypes.DataModel.Input diff --git a/src/Artemis.UI/DefaultTypes/DataModel/Input/SKColorDataModelInputViewModel.cs b/src/Artemis.UI/DefaultTypes/DataModel/Input/SKColorDataModelInputViewModel.cs index 02c1beb5f..93aafd576 100644 --- a/src/Artemis.UI/DefaultTypes/DataModel/Input/SKColorDataModelInputViewModel.cs +++ b/src/Artemis.UI/DefaultTypes/DataModel/Input/SKColorDataModelInputViewModel.cs @@ -1,4 +1,4 @@ -using Artemis.Core.DataModelExpansions; +using Artemis.Core.Modules; using Artemis.UI.Shared; using SkiaSharp; diff --git a/src/Artemis.UI/DefaultTypes/DataModel/Input/StringDataModelInputViewModel.cs b/src/Artemis.UI/DefaultTypes/DataModel/Input/StringDataModelInputViewModel.cs index 284a3fd08..450664b01 100644 --- a/src/Artemis.UI/DefaultTypes/DataModel/Input/StringDataModelInputViewModel.cs +++ b/src/Artemis.UI/DefaultTypes/DataModel/Input/StringDataModelInputViewModel.cs @@ -1,4 +1,4 @@ -using Artemis.Core.DataModelExpansions; +using Artemis.Core.Modules; using Artemis.UI.Shared; namespace Artemis.UI.DefaultTypes.DataModel.Input diff --git a/src/Artemis.UI/Screens/Settings/Debug/Tabs/DataModelDebugViewModel.cs b/src/Artemis.UI/Screens/Settings/Debug/Tabs/DataModelDebugViewModel.cs index 32dbb01b5..7825cc03b 100644 --- a/src/Artemis.UI/Screens/Settings/Debug/Tabs/DataModelDebugViewModel.cs +++ b/src/Artemis.UI/Screens/Settings/Debug/Tabs/DataModelDebugViewModel.cs @@ -87,7 +87,7 @@ namespace Artemis.UI.Screens.Settings.Debug.Tabs protected override void OnClose() { _updateTimer.Dispose(); - base.OnClose(); + base.OnClose(); } #endregion @@ -109,6 +109,9 @@ namespace Artemis.UI.Screens.Settings.Debug.Tabs { _updateTimer.Stop(); _updateTimer.Elapsed -= OnUpdateTimerOnElapsed; + MainDataModel?.Dispose(); + MainDataModel = null; + _pluginManagementService.PluginFeatureEnabled -= OnPluginFeatureToggled; _pluginManagementService.PluginFeatureDisabled -= OnPluginFeatureToggled;