diff --git a/src/Artemis.Core/Models/Profile/DataBindings/DataBinding.cs b/src/Artemis.Core/Models/Profile/DataBindings/DataBinding.cs index acdf15530..54c63292f 100644 --- a/src/Artemis.Core/Models/Profile/DataBindings/DataBinding.cs +++ b/src/Artemis.Core/Models/Profile/DataBindings/DataBinding.cs @@ -177,7 +177,7 @@ namespace Artemis.Core var easingAmount = _easingProgress.TotalSeconds / EasingTime.TotalSeconds; return Converter.Interpolate(_previousValue, _currentValue, Easings.Interpolate(easingAmount, EasingFunction)); } - + #region Mode management /// @@ -218,7 +218,7 @@ namespace Artemis.Core } #endregion - + #region Storage /// @@ -262,7 +262,7 @@ namespace Artemis.Core public enum DataBindingModeType { /// - /// Disables the data binding + /// Disables the data binding /// None, @@ -272,8 +272,8 @@ namespace Artemis.Core Direct, /// - /// Replaces the layer property value with the data binding value + /// Replaces the layer property value with the data binding value /// - Conditional, + Conditional } } \ No newline at end of file diff --git a/src/Artemis.Core/Models/Profile/DataBindings/DataBindingRegistration.cs b/src/Artemis.Core/Models/Profile/DataBindings/DataBindingRegistration.cs index e1dea2169..6ef9dd14a 100644 --- a/src/Artemis.Core/Models/Profile/DataBindings/DataBindingRegistration.cs +++ b/src/Artemis.Core/Models/Profile/DataBindings/DataBindingRegistration.cs @@ -51,7 +51,7 @@ namespace Artemis.Core { return DataBinding; } - + /// public IDataBinding CreateDataBinding() { diff --git a/src/Artemis.Core/Models/Profile/DataBindings/Modes/ConditionalDataBinding.cs b/src/Artemis.Core/Models/Profile/DataBindings/Modes/ConditionalDataBinding.cs index 9d844bd9b..0e3cd309d 100644 --- a/src/Artemis.Core/Models/Profile/DataBindings/Modes/ConditionalDataBinding.cs +++ b/src/Artemis.Core/Models/Profile/DataBindings/Modes/ConditionalDataBinding.cs @@ -1,4 +1,7 @@ -using Artemis.Storage.Entities.Profile.DataBindings; +using System; +using System.Collections.Generic; +using System.Linq; +using Artemis.Storage.Entities.Profile.DataBindings; namespace Artemis.Core { @@ -7,42 +10,130 @@ namespace Artemis.Core /// public class ConditionalDataBinding : IDataBindingMode { + private readonly List> _conditions = new List>(); + private bool _disposed; + internal ConditionalDataBinding(DataBinding dataBinding, ConditionalDataBindingEntity entity) { DataBinding = dataBinding; Entity = entity; } + internal ConditionalDataBindingEntity Entity { get; } + + /// + /// Gets a list of conditions applied to this data binding + /// + public IReadOnlyList> Conditions => _conditions.AsReadOnly(); + /// public DataBinding DataBinding { get; } /// public TProperty GetValue(TProperty baseValue) { - return default; + if (_disposed) + throw new ObjectDisposedException("ConditionalDataBinding"); + + var condition = Conditions.FirstOrDefault(c => c.Evaluate()); + return condition == null ? baseValue : condition.Value; } - internal ConditionalDataBindingEntity Entity { get; } - - #region Storage - - /// - public void Load() - { - } - - /// - public void Save() - { - } - - #endregion - #region IDisposable /// public void Dispose() { + _disposed = true; + + foreach (var dataBindingCondition in Conditions) + dataBindingCondition.Dispose(); + } + + #endregion + + #region Values + + /// + /// Adds a condition to the conditional data binding's collection + /// + /// The newly created + public DataBindingCondition AddCondition() + { + if (_disposed) + throw new ObjectDisposedException("ConditionalDataBinding"); + + var condition = new DataBindingCondition(this); + _conditions.Add(condition); + + ApplyOrder(); + OnConditionsUpdated(); + + return condition; + } + + /// + /// Removes a condition from the conditional data binding's collection and disposes it + /// + /// + public void RemoveCondition(DataBindingCondition condition) + { + if (_disposed) + throw new ObjectDisposedException("ConditionalDataBinding"); + if (!_conditions.Contains(condition)) + return; + + _conditions.Remove(condition); + condition.Dispose(); + + ApplyOrder(); + OnConditionsUpdated(); + } + + internal void ApplyOrder() + { + _conditions.Sort((a, b) => a.Order.CompareTo(b.Order)); + for (var index = 0; index < _conditions.Count; index++) + { + var condition = _conditions[index]; + condition.Order = index + 1; + } + } + + #endregion + + + #region Storage + + /// + public void Load() + { + foreach (var dataBindingConditionEntity in Entity.Values) + _conditions.Add(new DataBindingCondition(this, dataBindingConditionEntity)); + + ApplyOrder(); + } + + /// + public void Save() + { + Entity.Values.Clear(); + foreach (var dataBindingCondition in Conditions) + dataBindingCondition.Save(); + } + + #endregion + + #region Events + + /// + /// Occurs when a condition is added or removed + /// + public event EventHandler ConditionsUpdated; + + protected virtual void OnConditionsUpdated() + { + ConditionsUpdated?.Invoke(this, EventArgs.Empty); } #endregion diff --git a/src/Artemis.Core/Models/Profile/DataBindings/Modes/DataBindingCondition.cs b/src/Artemis.Core/Models/Profile/DataBindings/Modes/DataBindingCondition.cs new file mode 100644 index 000000000..49f08ee8c --- /dev/null +++ b/src/Artemis.Core/Models/Profile/DataBindings/Modes/DataBindingCondition.cs @@ -0,0 +1,107 @@ +using System; +using Artemis.Storage.Entities.Profile.DataBindings; +using Newtonsoft.Json; + +namespace Artemis.Core +{ + /// + public class DataBindingCondition : IDataBindingCondition + { + private bool _disposed; + + /// + /// Creates a new instance of the class + /// + /// The conditional data binding this condition is applied too + public DataBindingCondition(ConditionalDataBinding conditionalDataBinding) + { + ConditionalDataBinding = conditionalDataBinding ?? throw new ArgumentNullException(nameof(conditionalDataBinding)); + Order = conditionalDataBinding.Conditions.Count + 1; + Entity = new DataBindingConditionEntity(); + Save(); + } + + internal DataBindingCondition(ConditionalDataBinding conditionalDataBinding, DataBindingConditionEntity entity) + { + ConditionalDataBinding = conditionalDataBinding ?? throw new ArgumentNullException(nameof(conditionalDataBinding)); + Entity = entity; + Load(); + } + + /// + /// Gets the conditional data binding this condition is applied to + /// + public ConditionalDataBinding ConditionalDataBinding { get; } + + /// + /// Gets the position at which the modifier appears on the data binding + /// + public int Order { get; internal set; } + + /// + /// Gets or sets the value to be applied when the condition is met + /// + public TProperty Value { get; set; } + + /// + /// Gets the root group of the condition that must be met + /// + public DataModelConditionGroup Condition { get; private set; } + + internal DataBindingConditionEntity Entity { get; set; } + + /// + public bool Evaluate() + { + return Condition.Evaluate(); + } + + /// + public void Save() + { + if (_disposed) + throw new ObjectDisposedException("DataBindingCondition"); + + if (!ConditionalDataBinding.Entity.Values.Contains(Entity)) + ConditionalDataBinding.Entity.Values.Add(Entity); + + Entity.Condition = Condition.Entity; + Condition.Save(); + + Entity.Value = JsonConvert.SerializeObject(Value); + Entity.Order = Order; + } + + /// + public void Load() + { + if (_disposed) + throw new ObjectDisposedException("DataBindingCondition"); + + Condition = Entity.Condition != null + ? new DataModelConditionGroup(null, Entity.Condition) + : new DataModelConditionGroup(null); + + Value = JsonConvert.DeserializeObject(Entity.Value); + Order = Entity.Order; + } + + /// + public void Dispose() + { + _disposed = true; + + Condition.Dispose(); + } + + /// + /// Updates the order and resorts the Conditions list in the + /// + /// + public void UpdateOrder(int order) + { + Order = order; + ConditionalDataBinding.ApplyOrder(); + } + } +} \ No newline at end of file diff --git a/src/Artemis.Core/Models/Profile/DataBindings/DataBindingModifier.cs b/src/Artemis.Core/Models/Profile/DataBindings/Modes/DataBindingModifier.cs similarity index 95% rename from src/Artemis.Core/Models/Profile/DataBindings/DataBindingModifier.cs rename to src/Artemis.Core/Models/Profile/DataBindings/Modes/DataBindingModifier.cs index d8b2c117d..391027097 100644 --- a/src/Artemis.Core/Models/Profile/DataBindings/DataBindingModifier.cs +++ b/src/Artemis.Core/Models/Profile/DataBindings/Modes/DataBindingModifier.cs @@ -12,14 +12,10 @@ namespace Artemis.Core { private bool _disposed; - /// - /// Creates a new instance of the class - /// - /// The direct data binding the modifier is to be applied to - /// The type of the parameter, can either be dynamic (based on a data model value) or static - public DataBindingModifier(DirectDataBinding directDataBinding, ProfileRightSideType parameterType) + internal DataBindingModifier(DirectDataBinding directDataBinding, ProfileRightSideType parameterType) { DirectDataBinding = directDataBinding ?? throw new ArgumentNullException(nameof(directDataBinding)); + Order = directDataBinding.Modifiers.Count + 1; ParameterType = parameterType; Entity = new DataBindingModifierEntity(); Initialize(); @@ -40,7 +36,7 @@ namespace Artemis.Core public DataBindingModifierType ModifierType { get; private set; } /// - /// Gets the direct data binding this modifier is applied to + /// Gets the direct data binding this modifier is applied to /// public DirectDataBinding DirectDataBinding { get; } @@ -123,6 +119,17 @@ namespace Artemis.Core // Parameter is done during initialize } + /// + public void Dispose() + { + _disposed = true; + + DataBindingModifierTypeStore.DataBindingModifierAdded -= DataBindingModifierTypeStoreOnDataBindingModifierAdded; + DataBindingModifierTypeStore.DataBindingModifierRemoved -= DataBindingModifierTypeStoreOnDataBindingModifierRemoved; + DataModelStore.DataModelAdded -= DataModelStoreOnDataModelAdded; + DataModelStore.DataModelRemoved -= DataModelStoreOnDataModelRemoved; + } + /// /// Applies the modifier to the provided value /// @@ -339,23 +346,12 @@ namespace Artemis.Core private void DataModelStoreOnDataModelRemoved(object sender, DataModelStoreEvent e) { - if (e.Registration.DataModel != ParameterDataModel) + if (e.Registration.DataModel != ParameterDataModel) return; ParameterDataModel = null; CompiledParameterAccessor = null; } #endregion - - /// - public void Dispose() - { - _disposed = true; - - DataBindingModifierTypeStore.DataBindingModifierAdded -= DataBindingModifierTypeStoreOnDataBindingModifierAdded; - DataBindingModifierTypeStore.DataBindingModifierRemoved -= DataBindingModifierTypeStoreOnDataBindingModifierRemoved; - DataModelStore.DataModelAdded -= DataModelStoreOnDataModelAdded; - DataModelStore.DataModelRemoved -= DataModelStoreOnDataModelRemoved; - } } } \ No newline at end of file diff --git a/src/Artemis.Core/Models/Profile/DataBindings/DataBindingModifierType.cs b/src/Artemis.Core/Models/Profile/DataBindings/Modes/DataBindingModifierType.cs similarity index 100% rename from src/Artemis.Core/Models/Profile/DataBindings/DataBindingModifierType.cs rename to src/Artemis.Core/Models/Profile/DataBindings/Modes/DataBindingModifierType.cs diff --git a/src/Artemis.Core/Models/Profile/DataBindings/Modes/DirectDataBinding.cs b/src/Artemis.Core/Models/Profile/DataBindings/Modes/DirectDataBinding.cs index 4ed07a17c..75e3c8c82 100644 --- a/src/Artemis.Core/Models/Profile/DataBindings/Modes/DirectDataBinding.cs +++ b/src/Artemis.Core/Models/Profile/DataBindings/Modes/DirectDataBinding.cs @@ -24,9 +24,6 @@ namespace Artemis.Core Load(); } - /// - public DataBinding DataBinding { get; } - internal DirectDataBindingEntity Entity { get; } /// @@ -49,11 +46,14 @@ namespace Artemis.Core /// public Func CompiledTargetAccessor { get; private set; } + /// + public DataBinding DataBinding { get; } + /// public TProperty GetValue(TProperty baseValue) { if (_disposed) - throw new ObjectDisposedException("DataBinding"); + throw new ObjectDisposedException("DirectDataBinding"); if (CompiledTargetAccessor == null) return baseValue; @@ -91,6 +91,8 @@ namespace Artemis.Core // Modifiers foreach (var dataBindingModifierEntity in Entity.Modifiers) _modifiers.Add(new DataBindingModifier(this, dataBindingModifierEntity)); + + ApplyOrder(); } /// @@ -156,7 +158,7 @@ namespace Artemis.Core { return SourceDataModel?.GetTypeAtPath(SourcePropertyPath); } - + /// /// Updates the source of the data binding and re-compiles the expression /// @@ -165,7 +167,7 @@ namespace Artemis.Core public void UpdateSource(DataModel dataModel, string path) { if (_disposed) - throw new ObjectDisposedException("DataBinding"); + throw new ObjectDisposedException("DirectDataBinding"); if (dataModel != null && path == null) throw new ArtemisCoreException("If a data model is provided, a path is also required"); @@ -188,34 +190,47 @@ namespace Artemis.Core #region Modifiers /// - /// Adds a modifier to the data binding's collection + /// Adds a modifier to the direct data binding's collection /// + /// The type of the parameter, can either be dynamic (based on a data model value) or static public DataBindingModifier AddModifier(ProfileRightSideType type) { if (_disposed) - throw new ObjectDisposedException("DataBinding"); + throw new ObjectDisposedException("DirectDataBinding"); var modifier = new DataBindingModifier(this, type); _modifiers.Add(modifier); + + ApplyOrder(); OnModifiersUpdated(); return modifier; } /// - /// Removes a modifier from the data binding's collection and disposes it + /// Removes a modifier from the direct data binding's collection and disposes it /// public void RemoveModifier(DataBindingModifier modifier) { if (_disposed) - throw new ObjectDisposedException("DataBinding"); + throw new ObjectDisposedException("DirectDataBinding"); + if (!_modifiers.Contains(modifier)) + return; - if (_modifiers.Contains(modifier)) + _modifiers.Remove(modifier); + modifier.Dispose(); + + ApplyOrder(); + OnModifiersUpdated(); + } + + internal void ApplyOrder() + { + _modifiers.Sort((a, b) => a.Order.CompareTo(b.Order)); + for (var index = 0; index < _modifiers.Count; index++) { - _modifiers.Remove(modifier); - modifier.Dispose(); - - OnModifiersUpdated(); + var modifier = _modifiers[index]; + modifier.Order = index + 1; } } diff --git a/src/Artemis.Core/Models/Profile/DataBindings/Modes/IDataBindingCondition.cs b/src/Artemis.Core/Models/Profile/DataBindings/Modes/IDataBindingCondition.cs new file mode 100644 index 000000000..26ad9a9f2 --- /dev/null +++ b/src/Artemis.Core/Models/Profile/DataBindings/Modes/IDataBindingCondition.cs @@ -0,0 +1,15 @@ +using System; + +namespace Artemis.Core +{ + /// + /// Represents a condition and a value inside a + /// + public interface IDataBindingCondition : IStorageModel, IDisposable + { + /// + /// Evaluates the condition + /// + bool Evaluate(); + } +} \ No newline at end of file diff --git a/src/Artemis.Core/Models/Profile/DataBindings/Modes/IDataBindingMode.cs b/src/Artemis.Core/Models/Profile/DataBindings/Modes/IDataBindingMode.cs index d9cea1a86..e46a2aee9 100644 --- a/src/Artemis.Core/Models/Profile/DataBindings/Modes/IDataBindingMode.cs +++ b/src/Artemis.Core/Models/Profile/DataBindings/Modes/IDataBindingMode.cs @@ -3,7 +3,7 @@ namespace Artemis.Core { /// - /// Represents a data binding mode + /// Represents a data binding mode /// public interface IDataBindingMode : IStorageModel, IDisposable { @@ -19,4 +19,4 @@ namespace Artemis.Core /// TProperty GetValue(TProperty baseValue); } -} +} \ No newline at end of file diff --git a/src/Artemis.Core/Models/Profile/DataBindings/IDataBindingModifier.cs b/src/Artemis.Core/Models/Profile/DataBindings/Modes/IDataBindingModifier.cs similarity index 100% rename from src/Artemis.Core/Models/Profile/DataBindings/IDataBindingModifier.cs rename to src/Artemis.Core/Models/Profile/DataBindings/Modes/IDataBindingModifier.cs diff --git a/src/Artemis.Storage/Entities/Profile/DataBindings/ConditionalDataBindingEntity.cs b/src/Artemis.Storage/Entities/Profile/DataBindings/ConditionalDataBindingEntity.cs index 02a8768e3..c7fffcf19 100644 --- a/src/Artemis.Storage/Entities/Profile/DataBindings/ConditionalDataBindingEntity.cs +++ b/src/Artemis.Storage/Entities/Profile/DataBindings/ConditionalDataBindingEntity.cs @@ -6,9 +6,9 @@ namespace Artemis.Storage.Entities.Profile.DataBindings { public ConditionalDataBindingEntity() { - Values = new List(); + Values = new List(); } - public List Values { get; set; } + public List Values { get; set; } } } \ No newline at end of file diff --git a/src/Artemis.Storage/Entities/Profile/DataBindings/DataBindingConditionValueEntity.cs b/src/Artemis.Storage/Entities/Profile/DataBindings/DataBindingConditionEntity.cs similarity index 54% rename from src/Artemis.Storage/Entities/Profile/DataBindings/DataBindingConditionValueEntity.cs rename to src/Artemis.Storage/Entities/Profile/DataBindings/DataBindingConditionEntity.cs index 8f1c9004b..7fb0fc611 100644 --- a/src/Artemis.Storage/Entities/Profile/DataBindings/DataBindingConditionValueEntity.cs +++ b/src/Artemis.Storage/Entities/Profile/DataBindings/DataBindingConditionEntity.cs @@ -2,9 +2,10 @@ namespace Artemis.Storage.Entities.Profile.DataBindings { - public class DataBindingConditionValueEntity + public class DataBindingConditionEntity { public string Value { get; set; } - public DataModelConditionGroupEntity RootGroup { get; set; } + public DataModelConditionGroupEntity Condition { get; set; } + public int Order { get; set; } } } \ No newline at end of file