1
0
mirror of https://github.com/Artemis-RGB/Artemis synced 2025-12-13 05:48:35 +00:00

Conditions - Moved non-list conditions to new paths API

Conditions - Move list conditions to new paths API (WIP)
This commit is contained in:
SpoinkyNL 2020-10-08 00:05:37 +02:00
parent 9417332a07
commit 725bb2a128
16 changed files with 168 additions and 273 deletions

View File

@ -15,7 +15,7 @@ namespace Artemis.Core
/// <summary> /// <summary>
/// Gets the parent of this part /// Gets the parent of this part
/// </summary> /// </summary>
public DataModelConditionPart Parent { get; internal set; } public DataModelConditionPart? Parent { get; internal set; }
/// <summary> /// <summary>
/// Gets the children of this part /// Gets the children of this part

View File

@ -95,6 +95,7 @@ namespace Artemis.Core
if (!typeof(IList).IsAssignableFrom(listType)) if (!typeof(IList).IsAssignableFrom(listType))
throw new ArtemisCoreException($"Data model of type {dataModel.GetType().Name} does not contain a list at path '{newPath}'"); throw new ArtemisCoreException($"Data model of type {dataModel.GetType().Name} does not contain a list at path '{newPath}'");
ListPath = newPath;
ListType = listType; ListType = listType;
IsPrimitiveList = listType.IsPrimitive || listType.IsEnum || listType == typeof(string); IsPrimitiveList = listType.IsPrimitive || listType.IsEnum || listType == typeof(string);
} }

View File

@ -1,6 +1,4 @@
using System; using System;
using System.Linq;
using System.Linq.Expressions;
using System.Reflection; using System.Reflection;
using Artemis.Core.DataModelExpansions; using Artemis.Core.DataModelExpansions;
using Artemis.Storage.Entities.Profile.Abstract; using Artemis.Storage.Entities.Profile.Abstract;
@ -41,8 +39,6 @@ namespace Artemis.Core
Initialize(); Initialize();
} }
internal DataModelConditionListPredicateEntity Entity { get; set; }
/// <summary> /// <summary>
/// Gets or sets the predicate type /// Gets or sets the predicate type
/// </summary> /// </summary>
@ -68,6 +64,8 @@ namespace Artemis.Core
/// </summary> /// </summary>
public object? RightStaticValue { get; private set; } public object? RightStaticValue { get; private set; }
internal DataModelConditionListPredicateEntity Entity { get; set; }
/// <summary> /// <summary>
/// Updates the left side of the predicate /// Updates the left side of the predicate
/// </summary> /// </summary>
@ -80,11 +78,12 @@ namespace Artemis.Core
throw new ArtemisCoreException($"List type {DataModelConditionList.ListType.Name} does not contain path {path}"); throw new ArtemisCoreException($"List type {DataModelConditionList.ListType.Name} does not contain path {path}");
LeftPath?.Dispose(); LeftPath?.Dispose();
LeftPath = new DataModelPath(new ListPredicateWrapperDataModel(), path); LeftPath = DataModelConditionList.ListType != null
? new DataModelPath(ListPredicateWrapperDataModel.Create(DataModelConditionList.ListType), path)
: null;
ValidateOperator(); ValidateOperator();
ValidateRightSide(); ValidateRightSide();
CreateExpression();
} }
/// <summary> /// <summary>
@ -99,9 +98,9 @@ namespace Artemis.Core
PredicateType = ListRightSideType.DynamicList; PredicateType = ListRightSideType.DynamicList;
RightPath?.Dispose(); RightPath?.Dispose();
RightPath = new DataModelPath(new ListPredicateWrapperDataModel(), path); RightPath = DataModelConditionList.ListType != null
? new DataModelPath(ListPredicateWrapperDataModel.Create(DataModelConditionList.ListType), path)
CreateExpression(); : null;
} }
/// <summary> /// <summary>
@ -118,37 +117,32 @@ namespace Artemis.Core
throw new ArtemisCoreException("If path is provided, a data model is also required"); throw new ArtemisCoreException("If path is provided, a data model is also required");
if (dataModel != null) if (dataModel != null)
{
if (!dataModel.ContainsPath(path)) if (!dataModel.ContainsPath(path))
throw new ArtemisCoreException($"Data model of type {dataModel.GetType().Name} does not contain a property at path '{path}'"); throw new ArtemisCoreException($"Data model of type {dataModel.GetType().Name} does not contain a property at path '{path}'");
}
PredicateType = ListRightSideType.Dynamic; PredicateType = ListRightSideType.Dynamic;
RightPath?.Dispose(); RightPath?.Dispose();
RightPath = new DataModelPath(dataModel, path); RightPath = new DataModelPath(dataModel, path);
CreateExpression();
} }
/// <summary> /// <summary>
/// Updates the right side of the predicate, makes the predicate static and re-compiles the expression /// Updates the right side of the predicate, makes the predicate static and re-compiles the expression
/// </summary> /// </summary>
/// <param name="staticValue">The right side value to use</param> /// <param name="staticValue">The right side value to use</param>
public void UpdateRightSideStatic(object staticValue) public void UpdateRightSideStatic(object? staticValue)
{ {
PredicateType = ListRightSideType.Static; PredicateType = ListRightSideType.Static;
RightPath?.Dispose(); RightPath?.Dispose();
RightPath = null; RightPath = null;
SetStaticValue(staticValue); SetStaticValue(staticValue);
CreateExpression();
} }
/// <summary> /// <summary>
/// Updates the operator of the predicate and re-compiles the expression /// Updates the operator of the predicate and re-compiles the expression
/// </summary> /// </summary>
/// <param name="conditionOperator"></param> /// <param name="conditionOperator"></param>
public void UpdateOperator(ConditionOperator conditionOperator) public void UpdateOperator(ConditionOperator? conditionOperator)
{ {
if (conditionOperator == null) if (conditionOperator == null)
{ {
@ -170,8 +164,6 @@ namespace Artemis.Core
if (conditionOperator.SupportsType(leftType)) if (conditionOperator.SupportsType(leftType))
Operator = conditionOperator; Operator = conditionOperator;
CreateExpression();
} }
/// <summary> /// <summary>
@ -205,6 +197,22 @@ namespace Artemis.Core
return true; return true;
} }
#region IDisposable
/// <inheritdoc />
protected override void Dispose(bool disposing)
{
ConditionOperatorStore.ConditionOperatorAdded -= ConditionOperatorStoreOnConditionOperatorAdded;
ConditionOperatorStore.ConditionOperatorRemoved -= ConditionOperatorStoreOnConditionOperatorRemoved;
LeftPath?.Dispose();
RightPath?.Dispose();
base.Dispose(disposing);
}
#endregion
internal override bool EvaluateObject(object target) internal override bool EvaluateObject(object target)
{ {
if (Operator == null || LeftPath == null || !LeftPath.IsValid) if (Operator == null || LeftPath == null || !LeftPath.IsValid)
@ -254,10 +262,12 @@ namespace Artemis.Core
internal override void Save() internal override void Save()
{ {
Entity.PredicateType = (int) PredicateType; Entity.PredicateType = (int) PredicateType;
Entity.LeftPropertyPath = LeftPropertyPath;
Entity.RightDataModelGuid = RightDataModel?.PluginInfo?.Guid; LeftPath?.Save();
Entity.RightPropertyPath = RightPropertyPath; Entity.LeftPath = LeftPath?.Entity;
RightPath?.Save();
Entity.RightPath = RightPath?.Entity;
Entity.RightStaticValue = JsonConvert.SerializeObject(RightStaticValue); Entity.RightStaticValue = JsonConvert.SerializeObject(RightStaticValue);
if (Operator != null) if (Operator != null)
@ -274,19 +284,12 @@ namespace Artemis.Core
private void ApplyParentList() private void ApplyParentList()
{ {
DataModelConditionPart current = Parent; DataModelConditionPart? current = Parent;
while (current != null) while (current != null)
{ {
if (current is DataModelConditionList parentList) if (current is DataModelConditionList parentList)
{ {
DataModelConditionList = parentList; DataModelConditionList = parentList;
if (LeftPropertyPath != null && !ListContainsInnerPath(LeftPropertyPath))
LeftPropertyPath = null;
if (RightPropertyPath != null && !ListContainsInnerPath(RightPropertyPath))
RightPropertyPath = null;
return; return;
} }
@ -299,46 +302,44 @@ namespace Artemis.Core
private void Initialize() private void Initialize()
{ {
DataModelStore.DataModelAdded += DataModelStoreOnDataModelAdded;
DataModelStore.DataModelRemoved += DataModelStoreOnDataModelRemoved;
ConditionOperatorStore.ConditionOperatorAdded += ConditionOperatorStoreOnConditionOperatorAdded; ConditionOperatorStore.ConditionOperatorAdded += ConditionOperatorStoreOnConditionOperatorAdded;
ConditionOperatorStore.ConditionOperatorRemoved += ConditionOperatorStoreOnConditionOperatorRemoved; ConditionOperatorStore.ConditionOperatorRemoved += ConditionOperatorStoreOnConditionOperatorRemoved;
// Left side // Left side
if (Entity.LeftPropertyPath != null && ListContainsInnerPath(Entity.LeftPropertyPath)) if (Entity.LeftPath != null)
UpdateLeftSide(Entity.LeftPropertyPath); {
LeftPath = DataModelConditionList.ListType != null
? new DataModelPath(ListPredicateWrapperDataModel.Create(DataModelConditionList.ListType), Entity.LeftPath)
: null;
}
// Operator // Operator
if (Entity.OperatorPluginGuid != null) if (Entity.OperatorPluginGuid != null)
{ {
ConditionOperator conditionOperator = ConditionOperatorStore.Get(Entity.OperatorPluginGuid.Value, Entity.OperatorType)?.ConditionOperator; ConditionOperator? conditionOperator = ConditionOperatorStore.Get(Entity.OperatorPluginGuid.Value, Entity.OperatorType)?.ConditionOperator;
if (conditionOperator != null) if (conditionOperator != null)
UpdateOperator(conditionOperator); UpdateOperator(conditionOperator);
} }
// Right side dynamic // Right side dynamic
if (PredicateType == ListRightSideType.Dynamic && Entity.RightDataModelGuid != null && Entity.RightPropertyPath != null) if (PredicateType == ListRightSideType.Dynamic && Entity.RightPath != null)
{ RightPath = new DataModelPath(null, Entity.RightPath);
DataModel dataModel = DataModelStore.Get(Entity.RightDataModelGuid.Value)?.DataModel;
if (dataModel != null && dataModel.ContainsPath(Entity.RightPropertyPath))
UpdateRightSideDynamic(dataModel, Entity.RightPropertyPath);
}
// Right side dynamic inside the list // Right side dynamic inside the list
else if (PredicateType == ListRightSideType.DynamicList && Entity.RightPropertyPath != null) else if (PredicateType == ListRightSideType.DynamicList && Entity.RightPath != null)
{ {
if (ListContainsInnerPath(Entity.RightPropertyPath)) RightPath = DataModelConditionList.ListType != null
UpdateRightSideDynamic(Entity.RightPropertyPath); ? new DataModelPath(ListPredicateWrapperDataModel.Create(DataModelConditionList.ListType), Entity.RightPath)
: null;
} }
// Right side static // Right side static
else if (PredicateType == ListRightSideType.Static && Entity.RightStaticValue != null) else if (PredicateType == ListRightSideType.Static && Entity.RightStaticValue != null)
{
try try
{ {
if (LeftPropertyPath != null) if (LeftPath != null && LeftPath.IsValid)
{ {
// Use the left side type so JSON.NET has a better idea what to do // Use the left side type so JSON.NET has a better idea what to do
Type leftSideType = GetTypeAtInnerPath(LeftPropertyPath); Type leftSideType = LeftPath.GetPropertyType()!;
object rightSideValue; object? rightSideValue;
try try
{ {
@ -363,73 +364,62 @@ namespace Artemis.Core
{ {
DeserializationLogger.LogListPredicateDeserializationFailure(this, e); DeserializationLogger.LogListPredicateDeserializationFailure(this, e);
} }
}
}
private void CreateExpression()
{
if (Operator == null)
return;
// If the operator does not support a right side, create a static expression because the right side will simply be null
if (PredicateType == ListRightSideType.DynamicList && Operator.SupportsRightSide)
CreateDynamicListAccessors();
else if (PredicateType == ListRightSideType.Dynamic && Operator.SupportsRightSide)
CreateDynamicAccessors();
else
CreateStaticAccessors();
} }
private void ValidateOperator() private void ValidateOperator()
{ {
if (LeftPropertyPath == null || Operator == null) if (LeftPath == null || !LeftPath.IsValid || Operator == null)
return; return;
Type leftSideType = GetTypeAtInnerPath(LeftPropertyPath); Type leftType = LeftPath.GetPropertyType()!;
if (!Operator.SupportsType(leftSideType)) if (!Operator.SupportsType(leftType))
Operator = null; Operator = null;
} }
private void ValidateRightSide() private void ValidateRightSide()
{ {
Type leftSideType = GetTypeAtInnerPath(LeftPropertyPath); Type? leftType = LeftPath?.GetPropertyType();
if (PredicateType == ListRightSideType.Dynamic) if (PredicateType == ListRightSideType.Dynamic)
{ {
if (RightDataModel == null) if (RightPath == null || !RightPath.IsValid)
return; return;
Type rightSideType = RightDataModel.GetTypeAtPath(RightPropertyPath); Type rightSideType = RightPath.GetPropertyType()!;
if (!leftSideType.IsCastableFrom(rightSideType)) if (leftType != null && !leftType.IsCastableFrom(rightSideType))
UpdateRightSideDynamic(null, null); UpdateRightSideDynamic(null, null);
} }
else if (PredicateType == ListRightSideType.DynamicList) else if (PredicateType == ListRightSideType.DynamicList)
{ {
if (RightPropertyPath == null) if (RightPath == null || !RightPath.IsValid)
return; return;
Type rightSideType = GetTypeAtInnerPath(RightPropertyPath); Type rightSideType = RightPath.GetPropertyType()!;
if (!leftSideType.IsCastableFrom(rightSideType)) if (leftType != null && !leftType.IsCastableFrom(rightSideType))
UpdateRightSideDynamic(null); UpdateRightSideDynamic(null);
} }
else else
{ {
if (RightStaticValue != null && leftSideType.IsCastableFrom(RightStaticValue.GetType())) if (RightStaticValue != null && (leftType == null || leftType.IsCastableFrom(RightStaticValue.GetType())))
UpdateRightSideStatic(RightStaticValue); UpdateRightSideStatic(RightStaticValue);
else else
UpdateRightSideStatic(null); UpdateRightSideStatic(null);
} }
} }
private void SetStaticValue(object staticValue) private void SetStaticValue(object? staticValue)
{ {
RightPath?.Dispose();
RightPath = null;
// If the left side is empty simply apply the value, any validation will wait // If the left side is empty simply apply the value, any validation will wait
if (LeftPropertyPath == null) if (LeftPath == null || !LeftPath.IsValid)
{ {
RightStaticValue = staticValue; RightStaticValue = staticValue;
return; return;
} }
Type leftSideType = GetTypeAtInnerPath(LeftPropertyPath); // If the left path is valid we can expect a type
Type leftSideType = LeftPath.GetPropertyType()!;
// If not null ensure the types match and if not, convert it // If not null ensure the types match and if not, convert it
if (staticValue != null && staticValue.GetType() == leftSideType) if (staticValue != null && staticValue.GetType() == leftSideType)
@ -448,107 +438,12 @@ namespace Artemis.Core
if (!(path.Target is ListPredicateWrapperDataModel wrapper)) if (!(path.Target is ListPredicateWrapperDataModel wrapper))
throw new ArtemisCoreException("Data model condition list predicate has a path with an invalid target"); throw new ArtemisCoreException("Data model condition list predicate has a path with an invalid target");
wrapper.Value = target; wrapper.UntypedValue = target;
return path.GetValue(); return path.GetValue();
} }
private void CreateDynamicListAccessors()
{
if (LeftPropertyPath == null || RightPropertyPath == null || Operator == null)
return;
// List accessors share the same parameter because a list always contains one item per entry
ParameterExpression leftSideParameter = Expression.Parameter(typeof(object), "listItem");
Expression leftSideAccessor = CreateListAccessor(LeftPropertyPath, leftSideParameter);
Expression rightSideAccessor = CreateListAccessor(RightPropertyPath, leftSideParameter);
// A conversion may be required if the types differ
// This can cause issues if the DataModelConditionOperator wasn't accurate in it's supported types but that is not a concern here
if (rightSideAccessor.Type != leftSideAccessor.Type)
rightSideAccessor = Expression.Convert(rightSideAccessor, leftSideAccessor.Type);
LeftSideAccessor = Expression.Lambda<Func<object, object>>(leftSideAccessor, leftSideParameter).Compile();
RightSideAccessor = Expression.Lambda<Func<object, object>>(rightSideAccessor, leftSideParameter).Compile();
}
private void CreateDynamicAccessors()
{
if (LeftPropertyPath == null || RightPropertyPath == null || RightDataModel == null || Operator == null)
return;
// List accessors share the same parameter because a list always contains one item per entry
ParameterExpression leftSideParameter = Expression.Parameter(typeof(object), "listItem");
Expression leftSideAccessor = CreateListAccessor(LeftPropertyPath, leftSideParameter);
Expression rightSideAccessor = ExpressionUtilities.CreateDataModelAccessor(RightDataModel, RightPropertyPath, "right", out ParameterExpression rightSideParameter);
// A conversion may be required if the types differ
// This can cause issues if the DataModelConditionOperator wasn't accurate in it's supported types but that is not a concern here
if (rightSideAccessor.Type != leftSideAccessor.Type)
rightSideAccessor = Expression.Convert(rightSideAccessor, leftSideAccessor.Type);
LeftSideAccessor = Expression.Lambda<Func<object, object>>(leftSideAccessor, leftSideParameter).Compile();
RightSideAccessor = Expression.Lambda<Func<object, object>>(rightSideAccessor, rightSideParameter).Compile();
}
private void CreateStaticAccessors()
{
if (!DataModelConditionList.IsPrimitiveList && LeftPropertyPath == null || Operator == null)
return;
// List accessors share the same parameter because a list always contains one item per entry
ParameterExpression leftSideParameter = Expression.Parameter(typeof(object), "listItem");
Expression leftSideAccessor = DataModelConditionList.IsPrimitiveList
? Expression.Convert(leftSideParameter, DataModelConditionList.ListType)
: CreateListAccessor(LeftPropertyPath, leftSideParameter);
LeftSideAccessor = Expression.Lambda<Func<object, object>>(leftSideAccessor, leftSideParameter).Compile();
RightSideAccessor = null;
}
private Expression CreateListAccessor(string path, ParameterExpression listParameter)
{
// Create an expression that checks every part of the path for null
// In the same iteration, create the accessor
Expression source = Expression.Convert(listParameter, DataModelConditionList.ListType);
return ExpressionUtilities.CreateNullCheckedAccessor(source, path);
}
#region IDisposable
/// <inheritdoc />
protected override void Dispose(bool disposing)
{
DataModelStore.DataModelAdded -= DataModelStoreOnDataModelAdded;
DataModelStore.DataModelRemoved -= DataModelStoreOnDataModelRemoved;
ConditionOperatorStore.ConditionOperatorAdded -= ConditionOperatorStoreOnConditionOperatorAdded;
ConditionOperatorStore.ConditionOperatorRemoved -= ConditionOperatorStoreOnConditionOperatorRemoved;
LeftPath?.Dispose();
RightPath?.Dispose();
base.Dispose(disposing);
}
#endregion
#region Event handlers #region Event handlers
private void DataModelStoreOnDataModelAdded(object sender, DataModelStoreEvent e)
{
DataModel dataModel = e.Registration.DataModel;
if (dataModel.PluginInfo.Guid == Entity.RightDataModelGuid && dataModel.ContainsPath(Entity.RightPropertyPath))
UpdateRightSideDynamic(dataModel, Entity.RightPropertyPath);
}
private void DataModelStoreOnDataModelRemoved(object sender, DataModelStoreEvent e)
{
if (RightDataModel == e.Registration.DataModel)
{
RightSideAccessor = null;
RightDataModel = null;
}
}
private void ConditionOperatorStoreOnConditionOperatorAdded(object sender, ConditionOperatorStoreEvent e) private void ConditionOperatorStoreOnConditionOperatorAdded(object sender, ConditionOperatorStoreEvent e)
{ {
ConditionOperator conditionOperator = e.Registration.ConditionOperator; ConditionOperator conditionOperator = e.Registration.ConditionOperator;

View File

@ -240,8 +240,11 @@ namespace Artemis.Core
Entity.RightStaticValue = JsonConvert.SerializeObject(RightStaticValue); Entity.RightStaticValue = JsonConvert.SerializeObject(RightStaticValue);
Entity.OperatorPluginGuid = Operator?.PluginInfo?.Guid; if (Operator != null)
Entity.OperatorType = Operator?.GetType().Name; {
Entity.OperatorPluginGuid = Operator.PluginInfo.Guid;
Entity.OperatorType = Operator.GetType().Name;
}
} }
internal void Initialize() internal void Initialize()
@ -250,7 +253,8 @@ namespace Artemis.Core
ConditionOperatorStore.ConditionOperatorRemoved += ConditionOperatorStoreOnConditionOperatorRemoved; ConditionOperatorStore.ConditionOperatorRemoved += ConditionOperatorStoreOnConditionOperatorRemoved;
// Left side // Left side
if (Entity.LeftPath != null) LeftPath = new DataModelPath(null, Entity.LeftPath); if (Entity.LeftPath != null)
LeftPath = new DataModelPath(null, Entity.LeftPath);
// Operator // Operator
if (Entity.OperatorPluginGuid != null) if (Entity.OperatorPluginGuid != null)

View File

@ -1,9 +1,24 @@
using Artemis.Core.DataModelExpansions; using System;
using Artemis.Core.DataModelExpansions;
namespace Artemis.Core namespace Artemis.Core
{ {
internal class ListPredicateWrapperDataModel : DataModel internal class ListPredicateWrapperDataModel<T> : ListPredicateWrapperDataModel
{ {
public object Value { get; set; } public T Value => (UntypedValue is T typedValue ? typedValue : default)!;
}
public abstract class ListPredicateWrapperDataModel : DataModel
{
public object? UntypedValue { get; set; }
public static ListPredicateWrapperDataModel Create(Type type)
{
object? instance = Activator.CreateInstance(typeof(ListPredicateWrapperDataModel<>).MakeGenericType(type));
if (instance == null)
throw new ArtemisCoreException($"Failed to create an instance of ListPredicateWrapperDataModel<T> for type {type.Name}");
return (ListPredicateWrapperDataModel) instance;
}
} }
} }

View File

@ -29,9 +29,9 @@ namespace Artemis.Core
_logger.Warning( _logger.Warning(
exception, exception,
"Failed to deserialize display condition list predicate {list} => {left} {operator} {right}", "Failed to deserialize display condition list predicate {list} => {left} {operator} {right}",
dataModelConditionPredicate.Entity.LeftPropertyPath, dataModelConditionPredicate.Entity.LeftPath?.Path,
dataModelConditionPredicate.Entity.OperatorType, dataModelConditionPredicate.Entity.OperatorType,
dataModelConditionPredicate.Entity.RightPropertyPath dataModelConditionPredicate.Entity.RightPath?.Path
); );
} }

View File

@ -7,15 +7,14 @@ namespace Artemis.Storage.Entities.Profile.Conditions
{ {
public int PredicateType { get; set; } public int PredicateType { get; set; }
public string LeftPropertyPath { get; set; } public DataModelPathEntity LeftPath { get; set; }
public DataModelPathEntity RightPath { get; set; }
public Guid? RightDataModelGuid { get; set; }
public string RightPropertyPath { get; set; }
// Stored as a string to be able to control serialization and deserialization ourselves // Stored as a string to be able to control serialization and deserialization ourselves
public string RightStaticValue { get; set; } public string RightStaticValue { get; set; }
public string OperatorType { get; set; } public string OperatorType { get; set; }
public Guid? OperatorPluginGuid { get; set; } public Guid? OperatorPluginGuid { get; set; }
} }
} }

View File

@ -1,5 +1,5 @@
using System; using System;
using Artemis.Core.DataModelExpansions; using Artemis.Core;
using Artemis.UI.Shared.Services; using Artemis.UI.Shared.Services;
namespace Artemis.UI.Shared namespace Artemis.UI.Shared
@ -10,9 +10,9 @@ namespace Artemis.UI.Shared
private int _index; private int _index;
private Type _listType; private Type _listType;
public DataModelListPropertiesViewModel(DataModel dataModel, object listItem) : base(null, null, null) public DataModelListPropertiesViewModel(object listItem) : base(null, null, null)
{ {
DataModel = dataModel; DataModel = ListPredicateWrapperDataModel.Create(listItem.GetType());
ListType = listItem.GetType(); ListType = listItem.GetType();
DisplayValue = listItem; DisplayValue = listItem;
} }
@ -44,7 +44,7 @@ namespace Artemis.UI.Shared
return; return;
ListType = DisplayValue.GetType(); ListType = DisplayValue.GetType();
PopulateProperties(dataModelUIService, DisplayValue); PopulateProperties(dataModelUIService);
foreach (DataModelVisualizationViewModel dataModelVisualizationViewModel in Children) foreach (DataModelVisualizationViewModel dataModelVisualizationViewModel in Children)
dataModelVisualizationViewModel.Update(dataModelUIService); dataModelVisualizationViewModel.Update(dataModelUIService);
} }

View File

@ -1,5 +1,5 @@
using System; using System;
using Artemis.Core.DataModelExpansions; using Artemis.Core;
using Artemis.UI.Shared.Services; using Artemis.UI.Shared.Services;
namespace Artemis.UI.Shared namespace Artemis.UI.Shared
@ -9,17 +9,17 @@ namespace Artemis.UI.Shared
private int _index; private int _index;
private Type _listType; private Type _listType;
public DataModelListPropertyViewModel(DataModel dataModel, object listItem, DataModelDisplayViewModel displayViewModel) : base(null, null, null) public DataModelListPropertyViewModel(object listItem, DataModelDisplayViewModel displayViewModel) : base(null, null, null)
{ {
DataModel = dataModel; DataModel = ListPredicateWrapperDataModel.Create(listItem.GetType());
ListType = listItem.GetType(); ListType = listItem.GetType();
DisplayValue = listItem; DisplayValue = listItem;
DisplayViewModel = displayViewModel; DisplayViewModel = displayViewModel;
} }
public DataModelListPropertyViewModel(DataModel dataModel, object listItem) : base(null, null, null) public DataModelListPropertyViewModel(object listItem) : base(null, null, null)
{ {
DataModel = dataModel; DataModel = ListPredicateWrapperDataModel.Create(listItem.GetType());
ListType = listItem.GetType(); ListType = listItem.GetType();
DisplayValue = listItem; DisplayValue = listItem;
} }

View File

@ -11,7 +11,6 @@ namespace Artemis.UI.Shared
{ {
private string _count; private string _count;
private IList _list; private IList _list;
private DataModelVisualizationViewModel _listTypePropertyViewModel;
internal DataModelListViewModel(DataModel dataModel, DataModelVisualizationViewModel parent, DataModelPath dataModelPath) : base(dataModel, parent, dataModelPath) internal DataModelListViewModel(DataModel dataModel, DataModelVisualizationViewModel parent, DataModelPath dataModelPath) : base(dataModel, parent, dataModelPath)
{ {
@ -44,8 +43,6 @@ namespace Artemis.UI.Shared
// Put an empty value into the list type property view model // Put an empty value into the list type property view model
if (viewModel is DataModelListPropertiesViewModel dataModelListClassViewModel) if (viewModel is DataModelListPropertiesViewModel dataModelListClassViewModel)
{ {
dataModelListClassViewModel.DisplayValue = Activator.CreateInstance(dataModelListClassViewModel.ListType);
dataModelListClassViewModel.Update(dataModelUIService);
return dataModelListClassViewModel; return dataModelListClassViewModel;
} }
@ -109,13 +106,13 @@ namespace Artemis.UI.Shared
// If a display VM was found, prefer to use that in any case // If a display VM was found, prefer to use that in any case
DataModelDisplayViewModel typeViewModel = dataModelUIService.GetDataModelDisplayViewModel(listType); DataModelDisplayViewModel typeViewModel = dataModelUIService.GetDataModelDisplayViewModel(listType);
if (typeViewModel != null) if (typeViewModel != null)
return new DataModelListPropertyViewModel(DataModel, listItem, typeViewModel); return new DataModelListPropertyViewModel(listItem, typeViewModel);
// For primitives, create a property view model, it may be null that is fine // For primitives, create a property view model, it may be null that is fine
if (listType.IsPrimitive || listType.IsEnum || listType == typeof(string)) if (listType.IsPrimitive || listType.IsEnum || listType == typeof(string))
return new DataModelListPropertyViewModel(DataModel, listItem); return new DataModelListPropertyViewModel(listItem);
// For other value types create a child view model // For other value types create a child view model
if (listType.IsClass || listType.IsStruct()) if (listType.IsClass || listType.IsStruct())
return new DataModelListPropertiesViewModel(DataModel, listItem); return new DataModelListPropertiesViewModel(listItem);
return null; return null;
} }

View File

@ -13,7 +13,7 @@ namespace Artemis.UI.Shared
public override void Update(IDataModelUIService dataModelUIService) public override void Update(IDataModelUIService dataModelUIService)
{ {
// Always populate properties // Always populate properties
PopulateProperties(dataModelUIService, null); PopulateProperties(dataModelUIService);
// Only update children if the parent is expanded // Only update children if the parent is expanded
if (Parent != null && !Parent.IsVisualizationExpanded && !Parent.IsRootViewModel) if (Parent != null && !Parent.IsVisualizationExpanded && !Parent.IsRootViewModel)

View File

@ -125,7 +125,7 @@ namespace Artemis.UI.Shared
} }
// If the type couldn't be retrieved either way, assume false // If the type couldn't be retrieved either way, assume false
Type type = DataModelPath.GetPropertyType(); Type type = DataModelPath?.GetPropertyType();
if (type == null) if (type == null)
{ {
IsMatchingFilteredTypes = false; IsMatchingFilteredTypes = false;
@ -178,18 +178,12 @@ namespace Artemis.UI.Shared
return 0; return 0;
} }
internal void PopulateProperties(IDataModelUIService dataModelUIService, object overrideValue) internal void PopulateProperties(IDataModelUIService dataModelUIService)
{ {
if (IsRootViewModel && overrideValue == null) if (IsRootViewModel)
return; return;
Type modelType; Type modelType = Parent.IsRootViewModel ? DataModel.GetType() : DataModelPath.GetPropertyType();
if (overrideValue != null)
modelType = overrideValue.GetType();
else if (Parent.IsRootViewModel)
modelType = DataModel.GetType();
else
modelType = DataModelPath.GetPropertyType();
// Add missing static children // Add missing static children
foreach (PropertyInfo propertyInfo in modelType.GetProperties(BindingFlags.Public | BindingFlags.Instance)) foreach (PropertyInfo propertyInfo in modelType.GetProperties(BindingFlags.Public | BindingFlags.Instance))
@ -200,17 +194,13 @@ namespace Artemis.UI.Shared
if (propertyInfo.GetCustomAttribute<DataModelIgnoreAttribute>() != null) if (propertyInfo.GetCustomAttribute<DataModelIgnoreAttribute>() != null)
continue; continue;
DataModelVisualizationViewModel child = CreateChild(dataModelUIService, childPath, GetChildDepth(), overrideValue); DataModelVisualizationViewModel child = CreateChild(dataModelUIService, childPath, GetChildDepth());
if (child != null) if (child != null)
Children.Add(child); Children.Add(child);
} }
// Remove static children that should be hidden // Remove static children that should be hidden
ReadOnlyCollection<PropertyInfo> hiddenProperties; ReadOnlyCollection<PropertyInfo> hiddenProperties = DataModel.GetHiddenProperties();
if (overrideValue != null && overrideValue is DataModel overrideValueDataModel)
hiddenProperties = overrideValueDataModel.GetHiddenProperties();
else
hiddenProperties = DataModel.GetHiddenProperties();
foreach (PropertyInfo hiddenProperty in hiddenProperties) foreach (PropertyInfo hiddenProperty in hiddenProperties)
{ {
string childPath = AppendToPath(hiddenProperty.Name); string childPath = AppendToPath(hiddenProperty.Name);
@ -220,11 +210,7 @@ namespace Artemis.UI.Shared
} }
// Add missing dynamic children // Add missing dynamic children
object value; object value = Parent.IsRootViewModel ? DataModel : DataModelPath.GetValue();
if (overrideValue != null)
value = overrideValue;
else
value = Parent.IsRootViewModel ? DataModel : DataModelPath.GetValue();
if (value is DataModel dataModel) if (value is DataModel dataModel)
{ {
foreach (KeyValuePair<string, DataModel> kvp in dataModel.DynamicDataModels) foreach (KeyValuePair<string, DataModel> kvp in dataModel.DynamicDataModels)
@ -233,7 +219,7 @@ namespace Artemis.UI.Shared
if (Children.Any(c => c.Path != null && c.Path.Equals(childPath))) if (Children.Any(c => c.Path != null && c.Path.Equals(childPath)))
continue; continue;
DataModelVisualizationViewModel child = CreateChild(dataModelUIService, childPath, GetChildDepth(), overrideValue); DataModelVisualizationViewModel child = CreateChild(dataModelUIService, childPath, GetChildDepth());
if (child != null) if (child != null)
Children.Add(child); Children.Add(child);
} }
@ -245,12 +231,12 @@ namespace Artemis.UI.Shared
Children.RemoveRange(toRemoveDynamic); Children.RemoveRange(toRemoveDynamic);
} }
private DataModelVisualizationViewModel CreateChild(IDataModelUIService dataModelUIService, string path, int depth, object overrideValue) private DataModelVisualizationViewModel CreateChild(IDataModelUIService dataModelUIService, string path, int depth)
{ {
if (depth > MaxDepth) if (depth > MaxDepth)
return null; return null;
DataModelPath dataModelPath = new DataModelPath(overrideValue ?? DataModel, path); DataModelPath dataModelPath = new DataModelPath(DataModel, path);
if (!dataModelPath.IsValid) if (!dataModelPath.IsValid)
return null; return null;

View File

@ -79,18 +79,6 @@ namespace Artemis.UI.Screens.ProfileEditor.Conditions
public DelegateCommand SelectOperatorCommand { get; } public DelegateCommand SelectOperatorCommand { get; }
public void Dispose()
{
if (!_isPrimitiveList)
{
LeftSideSelectionViewModel.PropertySelected -= LeftSideOnPropertySelected;
LeftSideSelectionViewModel.Dispose();
}
DisposeRightSideDynamic();
DisposeRightSideStatic();
}
public override void Delete() public override void Delete()
{ {
base.Delete(); base.Delete();
@ -123,7 +111,7 @@ namespace Artemis.UI.Screens.ProfileEditor.Conditions
public override void Update() public override void Update()
{ {
Guid? listDataModelGuid = DataModelConditionListPredicate.DataModelConditionList.ListPath.DataModelGuid; Guid? listDataModelGuid = DataModelConditionListPredicate.DataModelConditionList.ListPath?.DataModelGuid;
if (listDataModelGuid == null) if (listDataModelGuid == null)
return; return;
@ -132,7 +120,7 @@ namespace Artemis.UI.Screens.ProfileEditor.Conditions
LeftSideSelectionViewModel.FilterTypes = _supportedInputTypes.ToArray(); LeftSideSelectionViewModel.FilterTypes = _supportedInputTypes.ToArray();
LeftSideSelectionViewModel.ButtonBrush = new SolidColorBrush(Color.FromRgb(71, 108, 188)); LeftSideSelectionViewModel.ButtonBrush = new SolidColorBrush(Color.FromRgb(71, 108, 188));
LeftSideSelectionViewModel.SelectedPropertyViewModel = LeftSideSelectionViewModel.DataModelViewModel.GetChildByPath( LeftSideSelectionViewModel.SelectedPropertyViewModel = LeftSideSelectionViewModel.DataModelViewModel.GetChildByPath(
listDataModelGuid.Value, DataModelConditionListPredicate.LeftPropertyPath listDataModelGuid.Value, DataModelConditionListPredicate.DataModelConditionList.ListPath.Path
); );
} }
@ -142,14 +130,20 @@ namespace Artemis.UI.Screens.ProfileEditor.Conditions
// Get the supported operators // Get the supported operators
Operators.Clear(); Operators.Clear();
Operators.AddRange(_conditionOperatorService.GetConditionOperatorsForType(leftSideType)); Operators.AddRange(_conditionOperatorService.GetConditionOperatorsForType(leftSideType ?? typeof(object)));
if (DataModelConditionListPredicate.Operator == null) if (DataModelConditionListPredicate.Operator == null)
DataModelConditionListPredicate.UpdateOperator(Operators.FirstOrDefault(o => o.SupportsType(leftSideType))); DataModelConditionListPredicate.UpdateOperator(Operators.FirstOrDefault(o => o.SupportsType(leftSideType ?? typeof(object))));
SelectedOperator = DataModelConditionListPredicate.Operator; SelectedOperator = DataModelConditionListPredicate.Operator;
if (SelectedOperator == null || !SelectedOperator.SupportsRightSide)
{
DisposeRightSideStatic();
DisposeRightSideDynamic();
}
// Ensure the right side has the proper VM // Ensure the right side has the proper VM
if (DataModelConditionListPredicate.PredicateType == ListRightSideType.Dynamic || if ((DataModelConditionListPredicate.PredicateType == ListRightSideType.Dynamic ||
DataModelConditionListPredicate.PredicateType == ListRightSideType.DynamicList) DataModelConditionListPredicate.PredicateType == ListRightSideType.DynamicList) &&
SelectedOperator.SupportsRightSide)
{ {
DisposeRightSideStatic(); DisposeRightSideStatic();
if (RightSideSelectionViewModel == null) if (RightSideSelectionViewModel == null)
@ -164,20 +158,16 @@ namespace Artemis.UI.Screens.ProfileEditor.Conditions
RightSideSelectionViewModel.FilterTypes = new[] {leftSideType}; RightSideSelectionViewModel.FilterTypes = new[] {leftSideType};
if (DataModelConditionListPredicate.PredicateType == ListRightSideType.Dynamic) if (DataModelConditionListPredicate.PredicateType == ListRightSideType.Dynamic)
{
RightSideSelectionViewModel.PopulateSelectedPropertyViewModel( RightSideSelectionViewModel.PopulateSelectedPropertyViewModel(
DataModelConditionListPredicate.RightDataModel, DataModelConditionListPredicate.RightPath?.Target,
DataModelConditionListPredicate.RightPropertyPath DataModelConditionListPredicate.RightPath?.Path
); );
}
else else
{
RightSideSelectionViewModel.SelectedPropertyViewModel = RightSideSelectionViewModel.DataModelViewModel.GetChildByPath( RightSideSelectionViewModel.SelectedPropertyViewModel = RightSideSelectionViewModel.DataModelViewModel.GetChildByPath(
listDataModelGuid.Value, DataModelConditionListPredicate.RightPropertyPath listDataModelGuid.Value, DataModelConditionListPredicate.RightPath?.Path
); );
}
} }
else else if (SelectedOperator.SupportsRightSide)
{ {
DisposeRightSideDynamic(); DisposeRightSideDynamic();
if (RightSideInputViewModel == null) if (RightSideInputViewModel == null)
@ -205,16 +195,12 @@ namespace Artemis.UI.Screens.ProfileEditor.Conditions
public void ApplyRightSideDynamic() public void ApplyRightSideDynamic()
{ {
if (DataModelConditionListPredicate.PredicateType == ListRightSideType.Dynamic) if (DataModelConditionListPredicate.PredicateType == ListRightSideType.Dynamic)
{
DataModelConditionListPredicate.UpdateRightSideDynamic( DataModelConditionListPredicate.UpdateRightSideDynamic(
RightSideSelectionViewModel.SelectedPropertyViewModel.DataModel, RightSideSelectionViewModel.SelectedPropertyViewModel.DataModel,
RightSideSelectionViewModel.SelectedPropertyViewModel.Path RightSideSelectionViewModel.SelectedPropertyViewModel.Path
); );
}
else if (DataModelConditionListPredicate.PredicateType == ListRightSideType.DynamicList) else if (DataModelConditionListPredicate.PredicateType == ListRightSideType.DynamicList)
{
DataModelConditionListPredicate.UpdateRightSideDynamic(RightSideSelectionViewModel.SelectedPropertyViewModel.Path); DataModelConditionListPredicate.UpdateRightSideDynamic(RightSideSelectionViewModel.SelectedPropertyViewModel.Path);
}
_profileEditorService.UpdateSelectedProfileElement(); _profileEditorService.UpdateSelectedProfileElement();
Update(); Update();
@ -238,10 +224,10 @@ namespace Artemis.UI.Screens.ProfileEditor.Conditions
private DataModelVisualizationViewModel GetListDataModel() private DataModelVisualizationViewModel GetListDataModel()
{ {
DataModelPropertiesViewModel dataModel = _dataModelUIService.GetPluginDataModelVisualization(_profileEditorService.GetCurrentModule(), true); if (DataModelConditionListPredicate.DataModelConditionList.ListPath?.DataModelGuid == null)
if (DataModelConditionListPredicate.DataModelConditionList.ListPath.DataModelGuid == null) throw new ArtemisUIException("Failed to retrieve the list data model VM for this list predicate because it has no list path");
return null;
DataModelPropertiesViewModel dataModel = _dataModelUIService.GetPluginDataModelVisualization(_profileEditorService.GetCurrentModule(), true);
DataModelListViewModel listDataModel = (DataModelListViewModel) dataModel.GetChildByPath( DataModelListViewModel listDataModel = (DataModelListViewModel) dataModel.GetChildByPath(
DataModelConditionListPredicate.DataModelConditionList.ListPath.DataModelGuid.Value, DataModelConditionListPredicate.DataModelConditionList.ListPath.DataModelGuid.Value,
DataModelConditionListPredicate.DataModelConditionList.ListPath.Path DataModelConditionListPredicate.DataModelConditionList.ListPath.Path
@ -293,5 +279,17 @@ namespace Artemis.UI.Screens.ProfileEditor.Conditions
RightSideSelectionViewModel = null; RightSideSelectionViewModel = null;
} }
} }
public void Dispose()
{
if (!_isPrimitiveList)
{
LeftSideSelectionViewModel.PropertySelected -= LeftSideOnPropertySelected;
LeftSideSelectionViewModel.Dispose();
}
DisposeRightSideDynamic();
DisposeRightSideStatic();
}
} }
} }

View File

@ -107,7 +107,7 @@ namespace Artemis.UI.Screens.ProfileEditor.Conditions
public override void Update() public override void Update()
{ {
TargetSelectionViewModel.PopulateSelectedPropertyViewModel(DataModelConditionList.ListPath.Target, DataModelConditionList.ListPath.Path); TargetSelectionViewModel.PopulateSelectedPropertyViewModel(DataModelConditionList.ListPath?.Target, DataModelConditionList.ListPath?.Path);
NotifyOfPropertyChange(nameof(SelectedListOperator)); NotifyOfPropertyChange(nameof(SelectedListOperator));
// Remove VMs of effects no longer applied on the layer // Remove VMs of effects no longer applied on the layer

View File

@ -118,25 +118,24 @@ namespace Artemis.UI.Screens.ProfileEditor.Conditions
{ {
LeftSideSelectionViewModel.FilterTypes = _supportedInputTypes.ToArray(); LeftSideSelectionViewModel.FilterTypes = _supportedInputTypes.ToArray();
LeftSideSelectionViewModel.PopulateSelectedPropertyViewModel( LeftSideSelectionViewModel.PopulateSelectedPropertyViewModel(
DataModelConditionPredicate.LeftPath.Target as DataModel, DataModelConditionPredicate.LeftPath?.Target,
DataModelConditionPredicate.LeftPath.Path DataModelConditionPredicate.LeftPath?.Path
); );
Type leftSideType = LeftSideSelectionViewModel.SelectedPropertyViewModel?.DataModelPath?.GetPropertyType(); Type leftSideType = LeftSideSelectionViewModel.SelectedPropertyViewModel?.DataModelPath?.GetPropertyType();
// Get the supported operators // Get the supported operators
Operators.Clear(); Operators.Clear();
Operators.AddRange(_conditionOperatorService.GetConditionOperatorsForType(leftSideType)); Operators.AddRange(_conditionOperatorService.GetConditionOperatorsForType(leftSideType ?? typeof(object)));
if (DataModelConditionPredicate.Operator == null) if (DataModelConditionPredicate.Operator == null)
DataModelConditionPredicate.UpdateOperator(Operators.FirstOrDefault(o => o.SupportsType(leftSideType))); DataModelConditionPredicate.UpdateOperator(Operators.FirstOrDefault(o => o.SupportsType(leftSideType ?? typeof(object))));
SelectedOperator = DataModelConditionPredicate.Operator; SelectedOperator = DataModelConditionPredicate.Operator;
if (!SelectedOperator.SupportsRightSide) if (SelectedOperator == null || !SelectedOperator.SupportsRightSide)
{ {
DisposeRightSideStatic(); DisposeRightSideStatic();
DisposeRightSideDynamic(); DisposeRightSideDynamic();
} }
// Ensure the right side has the proper VM // Ensure the right side has the proper VM
Type targetType = LeftSideSelectionViewModel?.SelectedPropertyViewModel?.DataModelPath?.GetPropertyType();
if (DataModelConditionPredicate.PredicateType == ProfileRightSideType.Dynamic && SelectedOperator.SupportsRightSide) if (DataModelConditionPredicate.PredicateType == ProfileRightSideType.Dynamic && SelectedOperator.SupportsRightSide)
{ {
DisposeRightSideStatic(); DisposeRightSideStatic();
@ -148,24 +147,24 @@ namespace Artemis.UI.Screens.ProfileEditor.Conditions
} }
RightSideSelectionViewModel.PopulateSelectedPropertyViewModel( RightSideSelectionViewModel.PopulateSelectedPropertyViewModel(
DataModelConditionPredicate.RightPath.Target as DataModel, DataModelConditionPredicate.RightPath?.Target,
DataModelConditionPredicate.RightPath.Path DataModelConditionPredicate.RightPath?.Path
); );
RightSideSelectionViewModel.FilterTypes = new[] {targetType}; RightSideSelectionViewModel.FilterTypes = new[] {leftSideType};
} }
else if (SelectedOperator.SupportsRightSide) else if (SelectedOperator.SupportsRightSide)
{ {
DisposeRightSideDynamic(); DisposeRightSideDynamic();
if (RightSideInputViewModel == null) if (RightSideInputViewModel == null)
{ {
RightSideInputViewModel = _dataModelUIService.GetStaticInputViewModel(targetType); RightSideInputViewModel = _dataModelUIService.GetStaticInputViewModel(leftSideType);
RightSideInputViewModel.ButtonBrush = (Brush) Application.Current.FindResource("PrimaryHueMidBrush"); RightSideInputViewModel.ButtonBrush = (Brush) Application.Current.FindResource("PrimaryHueMidBrush");
RightSideInputViewModel.ValueUpdated += RightSideOnValueEntered; RightSideInputViewModel.ValueUpdated += RightSideOnValueEntered;
} }
RightSideInputViewModel.Value = DataModelConditionPredicate.RightStaticValue; RightSideInputViewModel.Value = DataModelConditionPredicate.RightStaticValue;
if (RightSideInputViewModel.TargetType != targetType) if (RightSideInputViewModel.TargetType != leftSideType)
RightSideInputViewModel.UpdateTargetType(targetType); RightSideInputViewModel.UpdateTargetType(leftSideType);
} }
} }
@ -213,7 +212,7 @@ namespace Artemis.UI.Screens.ProfileEditor.Conditions
ApplyLeftSide(); ApplyLeftSide();
} }
private void RightSideOnPropertySelected(object? sender, DataModelInputDynamicEventArgs e) private void RightSideOnPropertySelected(object sender, DataModelInputDynamicEventArgs e)
{ {
ApplyRightSideDynamic(); ApplyRightSideDynamic();
} }

View File

@ -207,6 +207,7 @@
<s:String x:Key="/Default/CodeInspection/Highlighting/InspectionSeverities/=SuggestVarOrType_005FElsewhere/@EntryIndexedValue">ERROR</s:String> <s:String x:Key="/Default/CodeInspection/Highlighting/InspectionSeverities/=SuggestVarOrType_005FElsewhere/@EntryIndexedValue">ERROR</s:String>
<s:String x:Key="/Default/CodeInspection/Highlighting/InspectionSeverities/=SuggestVarOrType_005FSimpleTypes/@EntryIndexedValue">ERROR</s:String> <s:String x:Key="/Default/CodeInspection/Highlighting/InspectionSeverities/=SuggestVarOrType_005FSimpleTypes/@EntryIndexedValue">ERROR</s:String>
<s:String x:Key="/Default/CodeInspection/Highlighting/InspectionSeverities/=SuggestVarOrType_005FBuiltInTypes/@EntryIndexedValue">ERROR</s:String> <s:String x:Key="/Default/CodeInspection/Highlighting/InspectionSeverities/=SuggestVarOrType_005FBuiltInTypes/@EntryIndexedValue">ERROR</s:String>
<s:String x:Key="/Default/CodeStyle/Naming/CSharpNaming/Abbreviations/=UI/@EntryIndexedValue">UI</s:String>
<s:Boolean x:Key="/Default/Environment/SettingsMigration/IsMigratorApplied/=JetBrains_002EReSharper_002EPsi_002ECSharp_002ECodeStyle_002ECSharpKeepExistingMigration/@EntryIndexedValue">True</s:Boolean> <s:Boolean x:Key="/Default/Environment/SettingsMigration/IsMigratorApplied/=JetBrains_002EReSharper_002EPsi_002ECSharp_002ECodeStyle_002ECSharpKeepExistingMigration/@EntryIndexedValue">True</s:Boolean>
<s:Boolean x:Key="/Default/Environment/SettingsMigration/IsMigratorApplied/=JetBrains_002EReSharper_002EPsi_002ECSharp_002ECodeStyle_002ECSharpPlaceEmbeddedOnSameLineMigration/@EntryIndexedValue">True</s:Boolean> <s:Boolean x:Key="/Default/Environment/SettingsMigration/IsMigratorApplied/=JetBrains_002EReSharper_002EPsi_002ECSharp_002ECodeStyle_002ECSharpPlaceEmbeddedOnSameLineMigration/@EntryIndexedValue">True</s:Boolean>
<s:Boolean x:Key="/Default/Environment/SettingsMigration/IsMigratorApplied/=JetBrains_002EReSharper_002EPsi_002ECSharp_002ECodeStyle_002ECSharpUseContinuousIndentInsideBracesMigration/@EntryIndexedValue">True</s:Boolean> <s:Boolean x:Key="/Default/Environment/SettingsMigration/IsMigratorApplied/=JetBrains_002EReSharper_002EPsi_002ECSharp_002ECodeStyle_002ECSharpUseContinuousIndentInsideBracesMigration/@EntryIndexedValue">True</s:Boolean>