Initial refactoring to support CommandManager

This commit is contained in:
Ben Wallis 2017-06-17 13:50:44 +01:00
parent b65fad0679
commit fee2a4dd99
26 changed files with 549 additions and 201 deletions

View File

@ -6,6 +6,7 @@ using Filtration.ItemFilterPreview.Tests.Properties;
using Filtration.ObjectModel; using Filtration.ObjectModel;
using Filtration.ObjectModel.BlockItemTypes; using Filtration.ObjectModel.BlockItemTypes;
using Filtration.ObjectModel.Enums; using Filtration.ObjectModel.Enums;
using Filtration.ObjectModel.Factories;
using Filtration.Parser.Services; using Filtration.Parser.Services;
using Moq; using Moq;
using NUnit.Framework; using NUnit.Framework;
@ -71,7 +72,12 @@ namespace Filtration.ItemFilterPreview.Tests.Services
//Arrange //Arrange
var testInputScriptFile = Resources.MuldiniFilterScript; var testInputScriptFile = Resources.MuldiniFilterScript;
var blockGroupHierarchyBuilder = new BlockGroupHierarchyBuilder(); var blockGroupHierarchyBuilder = new BlockGroupHierarchyBuilder();
var scriptTranslator = new ItemFilterScriptTranslator(new ItemFilterBlockTranslator(blockGroupHierarchyBuilder), blockGroupHierarchyBuilder); var mockItemFilterScriptFactory = new Mock<IItemFilterScriptFactory>();
mockItemFilterScriptFactory
.Setup(i => i.Create())
.Returns(new ItemFilterScript());
var scriptTranslator = new ItemFilterScriptTranslator(blockGroupHierarchyBuilder, new ItemFilterBlockTranslator(blockGroupHierarchyBuilder), mockItemFilterScriptFactory.Object);
var script = scriptTranslator.TranslateStringToItemFilterScript(testInputScriptFile); var script = scriptTranslator.TranslateStringToItemFilterScript(testInputScriptFile);
var testInputItem = new Item var testInputItem = new Item
@ -101,7 +107,11 @@ namespace Filtration.ItemFilterPreview.Tests.Services
//Arrange //Arrange
var testInputScriptFile = Resources.MuldiniFilterScript; var testInputScriptFile = Resources.MuldiniFilterScript;
var blockGroupHierarchyBuilder = new BlockGroupHierarchyBuilder(); var blockGroupHierarchyBuilder = new BlockGroupHierarchyBuilder();
var scriptTranslator = new ItemFilterScriptTranslator(new ItemFilterBlockTranslator(blockGroupHierarchyBuilder), blockGroupHierarchyBuilder); var mockItemFilterScriptFactory = new Mock<IItemFilterScriptFactory>();
mockItemFilterScriptFactory
.Setup(i => i.Create())
.Returns(new ItemFilterScript());
var scriptTranslator = new ItemFilterScriptTranslator(blockGroupHierarchyBuilder, new ItemFilterBlockTranslator(blockGroupHierarchyBuilder), mockItemFilterScriptFactory.Object);
var script = scriptTranslator.TranslateStringToItemFilterScript(testInputScriptFile); var script = scriptTranslator.TranslateStringToItemFilterScript(testInputScriptFile);
var testInputItems = new List<IItem> var testInputItems = new List<IItem>

View File

@ -0,0 +1,62 @@
using System.Collections.Generic;
namespace Filtration.ObjectModel.Commands
{
public interface ICommandManager
{
void ExecuteCommand(ICommand command);
void Undo(int undoLevels = 1);
void Redo(int redoLevels = 1);
}
public interface ICommandManagerInternal : ICommandManager
{
void SetScript(IItemFilterScriptInternal layout);
}
internal class CommandManager : ICommandManagerInternal
{
private readonly Stack<IUndoableCommand> _undoCommandStack = new Stack<IUndoableCommand>();
private readonly Stack<IUndoableCommand> _redoCommandStack = new Stack<IUndoableCommand>();
private IItemFilterScriptInternal _itemFilterScript;
public void SetScript(IItemFilterScriptInternal itemFilterScript)
{
_itemFilterScript = itemFilterScript;
}
public void ExecuteCommand(ICommand command)
{
command.Execute();
var undoableCommand = command as IUndoableCommand;
if (undoableCommand != null)
{
_undoCommandStack.Push(undoableCommand);
_redoCommandStack.Clear();
}
_itemFilterScript.SetIsDirty(true);
}
public void Undo(int undoLevels = 1)
{
for (var index = undoLevels; _undoCommandStack.Count > 0 && index > 0; --index)
{
var undoableCommand = _undoCommandStack.Pop();
undoableCommand.Undo();
_redoCommandStack.Push(undoableCommand);
}
_itemFilterScript.SetIsDirty(true);
}
public void Redo(int redoLevels = 1)
{
for (int index = redoLevels; _redoCommandStack.Count > 0 && index > 0; --index)
{
var undoableCommand = _redoCommandStack.Pop();
undoableCommand.Redo();
_undoCommandStack.Push(undoableCommand);
}
_itemFilterScript.SetIsDirty(true);
}
}
}

View File

@ -0,0 +1,7 @@
namespace Filtration.ObjectModel.Commands
{
public interface ICommand
{
void Execute();
}
}

View File

@ -0,0 +1,8 @@
namespace Filtration.ObjectModel.Commands
{
internal interface IUndoableCommand : ICommand
{
void Undo();
void Redo();
}
}

View File

@ -0,0 +1,9 @@
namespace Filtration.ObjectModel.Factories
{
public interface IItemFilterScriptFactory
{
IItemFilterScript Create();
void Release(IItemFilterScript itemFilterScript);
}
}

View File

@ -31,6 +31,12 @@
<WarningLevel>4</WarningLevel> <WarningLevel>4</WarningLevel>
</PropertyGroup> </PropertyGroup>
<ItemGroup> <ItemGroup>
<Reference Include="Castle.Core, Version=3.3.0.0, Culture=neutral, PublicKeyToken=407dd0808d44fbdc, processorArchitecture=MSIL">
<HintPath>..\packages\Castle.Core.3.3.0\lib\net45\Castle.Core.dll</HintPath>
</Reference>
<Reference Include="Castle.Windsor, Version=3.4.0.0, Culture=neutral, PublicKeyToken=407dd0808d44fbdc, processorArchitecture=MSIL">
<HintPath>..\packages\Castle.Windsor.3.4.0\lib\net45\Castle.Windsor.dll</HintPath>
</Reference>
<Reference Include="PresentationCore" /> <Reference Include="PresentationCore" />
<Reference Include="System" /> <Reference Include="System" />
<Reference Include="System.ComponentModel.DataAnnotations" /> <Reference Include="System.ComponentModel.DataAnnotations" />
@ -68,6 +74,9 @@
<Compile Include="BlockItemTypes\SoundBlockItem.cs" /> <Compile Include="BlockItemTypes\SoundBlockItem.cs" />
<Compile Include="BlockItemTypes\TextColorBlockItem.cs" /> <Compile Include="BlockItemTypes\TextColorBlockItem.cs" />
<Compile Include="BlockItemTypes\WidthBlockItem.cs" /> <Compile Include="BlockItemTypes\WidthBlockItem.cs" />
<Compile Include="Commands\CommandManager.cs" />
<Compile Include="Commands\ICommand.cs" />
<Compile Include="Commands\IUndoableCommand.cs" />
<Compile Include="Enums\BlockAction.cs" /> <Compile Include="Enums\BlockAction.cs" />
<Compile Include="Enums\BlockItemType.cs" /> <Compile Include="Enums\BlockItemType.cs" />
<Compile Include="Enums\FilterPredicateOperator.cs" /> <Compile Include="Enums\FilterPredicateOperator.cs" />
@ -77,6 +86,7 @@
<Compile Include="Enums\ThemeComponentType.cs" /> <Compile Include="Enums\ThemeComponentType.cs" />
<Compile Include="Extensions\EnumHelper.cs" /> <Compile Include="Extensions\EnumHelper.cs" />
<Compile Include="Extensions\ItemRarityExtensions.cs" /> <Compile Include="Extensions\ItemRarityExtensions.cs" />
<Compile Include="Factories\IItemFilterScriptFactory.cs" />
<Compile Include="FilteredItem.cs" /> <Compile Include="FilteredItem.cs" />
<Compile Include="IAudioVisualBlockItem.cs" /> <Compile Include="IAudioVisualBlockItem.cs" />
<Compile Include="IItemFilterBlockItem.cs" /> <Compile Include="IItemFilterBlockItem.cs" />
@ -97,6 +107,12 @@
<Compile Include="ThemeEditor\Theme.cs" /> <Compile Include="ThemeEditor\Theme.cs" />
<Compile Include="ThemeEditor\ThemeComponent.cs" /> <Compile Include="ThemeEditor\ThemeComponent.cs" />
<Compile Include="ThemeEditor\ThemeComponentCollection.cs" /> <Compile Include="ThemeEditor\ThemeComponentCollection.cs" />
<Compile Include="WindsorInstallers\CommandsInstaller.cs" />
<Compile Include="WindsorInstallers\ModelsInstaller.cs" />
</ItemGroup>
<ItemGroup />
<ItemGroup>
<None Include="packages.config" />
</ItemGroup> </ItemGroup>
<Import Project="$(MSBuildToolsPath)\Microsoft.CSharp.targets" /> <Import Project="$(MSBuildToolsPath)\Microsoft.CSharp.targets" />
<!-- To modify your build process, add your task inside one of the targets below and uncomment it. <!-- To modify your build process, add your task inside one of the targets below and uncomment it.

View File

@ -1,39 +1,62 @@
using System; using System;
using System.Collections.Generic; using System.Collections.Generic;
using System.Collections.ObjectModel; using System.Collections.ObjectModel;
using System.ComponentModel;
using System.Linq; using System.Linq;
using System.Runtime.CompilerServices;
using Filtration.ObjectModel.Annotations;
using Filtration.ObjectModel.BlockItemTypes; using Filtration.ObjectModel.BlockItemTypes;
using Filtration.ObjectModel.Commands;
using Filtration.ObjectModel.ThemeEditor; using Filtration.ObjectModel.ThemeEditor;
namespace Filtration.ObjectModel namespace Filtration.ObjectModel
{ {
public interface IItemFilterScript public interface IItemFilterScript : INotifyPropertyChanged
{ {
ICommandManager CommandManager { get; }
ObservableCollection<IItemFilterBlockBase> ItemFilterBlocks { get; } ObservableCollection<IItemFilterBlockBase> ItemFilterBlocks { get; }
ObservableCollection<ItemFilterBlockGroup> ItemFilterBlockGroups { get; } ObservableCollection<ItemFilterBlockGroup> ItemFilterBlockGroups { get; }
ThemeComponentCollection ThemeComponents { get; set; } ThemeComponentCollection ThemeComponents { get; set; }
string FilePath { get; set; } string FilePath { get; set; }
string Description { get; set; } string Description { get; set; }
DateTime DateModified { get; set; } DateTime DateModified { get; set; }
bool IsDirty { get; }
IItemFilterScriptSettings ItemFilterScriptSettings { get; } IItemFilterScriptSettings ItemFilterScriptSettings { get; }
List<string> Validate(); List<string> Validate();
void ReplaceColors(ReplaceColorsParameterSet replaceColorsParameterSet); void ReplaceColors(ReplaceColorsParameterSet replaceColorsParameterSet);
} }
public class ItemFilterScript : IItemFilterScript public interface IItemFilterScriptInternal : IItemFilterScript
{ {
public ItemFilterScript() void SetIsDirty(bool isDirty);
}
public class ItemFilterScript : IItemFilterScriptInternal
{
private bool _isDirty;
internal ItemFilterScript()
{ {
ItemFilterBlocks = new ObservableCollection<IItemFilterBlockBase>(); ItemFilterBlocks = new ObservableCollection<IItemFilterBlockBase>();
ItemFilterBlockGroups = new ObservableCollection<ItemFilterBlockGroup> ItemFilterBlockGroups = new ObservableCollection<ItemFilterBlockGroup>
{ {
new ItemFilterBlockGroup("Root", null) new ItemFilterBlockGroup("Root", null)
}; };
ThemeComponents = new ThemeComponentCollection { IsMasterCollection = true}; ThemeComponents = new ThemeComponentCollection { IsMasterCollection = true };
ItemFilterScriptSettings = new ItemFilterScriptSettings(ThemeComponents); ItemFilterScriptSettings = new ItemFilterScriptSettings(ThemeComponents);
} }
public ItemFilterScript(ICommandManagerInternal commandManager) : this()
{
CommandManager = commandManager;
commandManager.SetScript(this);
}
public ICommandManager CommandManager { get; }
public ObservableCollection<IItemFilterBlockBase> ItemFilterBlocks { get; } public ObservableCollection<IItemFilterBlockBase> ItemFilterBlocks { get; }
public ObservableCollection<ItemFilterBlockGroup> ItemFilterBlockGroups { get; } public ObservableCollection<ItemFilterBlockGroup> ItemFilterBlockGroups { get; }
@ -45,6 +68,22 @@ namespace Filtration.ObjectModel
public string Description { get; set; } public string Description { get; set; }
public DateTime DateModified { get; set; } public DateTime DateModified { get; set; }
public bool IsDirty
{
get => _isDirty;
private set
{
if (value == _isDirty) return;
_isDirty = value;
OnPropertyChanged();
}
}
public void SetIsDirty(bool isDirty)
{
IsDirty = isDirty;
}
public List<string> Validate() public List<string> Validate()
{ {
var validationErrors = new List<string>(); var validationErrors = new List<string>();
@ -106,5 +145,12 @@ namespace Filtration.ObjectModel
return true; return true;
} }
public event PropertyChangedEventHandler PropertyChanged;
[NotifyPropertyChangedInvocator]
protected virtual void OnPropertyChanged([CallerMemberName] string propertyName = null)
{
PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName));
}
} }
} }

View File

@ -1,4 +1,26 @@
using System; /* MIT License
Copyright (c) 2016 JetBrains http://www.jetbrains.com
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE. */
using System;
#pragma warning disable 1591 #pragma warning disable 1591
// ReSharper disable UnusedMember.Global // ReSharper disable UnusedMember.Global
@ -7,7 +29,6 @@
// ReSharper disable IntroduceOptionalParameters.Global // ReSharper disable IntroduceOptionalParameters.Global
// ReSharper disable MemberCanBeProtected.Global // ReSharper disable MemberCanBeProtected.Global
// ReSharper disable InconsistentNaming // ReSharper disable InconsistentNaming
// ReSharper disable CheckNamespace
namespace Filtration.ObjectModel.Annotations namespace Filtration.ObjectModel.Annotations
{ {
@ -16,32 +37,37 @@ namespace Filtration.ObjectModel.Annotations
/// so the check for <c>null</c> is necessary before its usage. /// so the check for <c>null</c> is necessary before its usage.
/// </summary> /// </summary>
/// <example><code> /// <example><code>
/// [CanBeNull] public object Test() { return null; } /// [CanBeNull] object Test() => null;
/// public void UseTest() { ///
/// void UseTest() {
/// var p = Test(); /// var p = Test();
/// var s = p.ToString(); // Warning: Possible 'System.NullReferenceException' /// var s = p.ToString(); // Warning: Possible 'System.NullReferenceException'
/// } /// }
/// </code></example> /// </code></example>
[AttributeUsage( [AttributeUsage(
AttributeTargets.Method | AttributeTargets.Parameter | AttributeTargets.Property | AttributeTargets.Method | AttributeTargets.Parameter | AttributeTargets.Property |
AttributeTargets.Delegate | AttributeTargets.Field | AttributeTargets.Event)] AttributeTargets.Delegate | AttributeTargets.Field | AttributeTargets.Event |
AttributeTargets.Class | AttributeTargets.Interface | AttributeTargets.GenericParameter)]
public sealed class CanBeNullAttribute : Attribute { } public sealed class CanBeNullAttribute : Attribute { }
/// <summary> /// <summary>
/// Indicates that the value of the marked element could never be <c>null</c>. /// Indicates that the value of the marked element could never be <c>null</c>.
/// </summary> /// </summary>
/// <example><code> /// <example><code>
/// [NotNull] public object Foo() { /// [NotNull] object Foo() {
/// return null; // Warning: Possible 'null' assignment /// return null; // Warning: Possible 'null' assignment
/// } /// }
/// </code></example> /// </code></example>
[AttributeUsage( [AttributeUsage(
AttributeTargets.Method | AttributeTargets.Parameter | AttributeTargets.Property | AttributeTargets.Method | AttributeTargets.Parameter | AttributeTargets.Property |
AttributeTargets.Delegate | AttributeTargets.Field | AttributeTargets.Event)] AttributeTargets.Delegate | AttributeTargets.Field | AttributeTargets.Event |
AttributeTargets.Class | AttributeTargets.Interface | AttributeTargets.GenericParameter)]
public sealed class NotNullAttribute : Attribute { } public sealed class NotNullAttribute : Attribute { }
/// <summary> /// <summary>
/// Indicates that collection or enumerable value does not contain null elements. /// Can be appplied to symbols of types derived from IEnumerable as well as to symbols of Task
/// and Lazy classes to indicate that the value of a collection item, of the Task.Result property
/// or of the Lazy.Value property can never be null.
/// </summary> /// </summary>
[AttributeUsage( [AttributeUsage(
AttributeTargets.Method | AttributeTargets.Parameter | AttributeTargets.Property | AttributeTargets.Method | AttributeTargets.Parameter | AttributeTargets.Property |
@ -49,7 +75,9 @@ namespace Filtration.ObjectModel.Annotations
public sealed class ItemNotNullAttribute : Attribute { } public sealed class ItemNotNullAttribute : Attribute { }
/// <summary> /// <summary>
/// Indicates that collection or enumerable value can contain null elements. /// Can be appplied to symbols of types derived from IEnumerable as well as to symbols of Task
/// and Lazy classes to indicate that the value of a collection item, of the Task.Result property
/// or of the Lazy.Value property can be null.
/// </summary> /// </summary>
[AttributeUsage( [AttributeUsage(
AttributeTargets.Method | AttributeTargets.Parameter | AttributeTargets.Property | AttributeTargets.Method | AttributeTargets.Parameter | AttributeTargets.Property |
@ -63,8 +91,9 @@ namespace Filtration.ObjectModel.Annotations
/// </summary> /// </summary>
/// <example><code> /// <example><code>
/// [StringFormatMethod("message")] /// [StringFormatMethod("message")]
/// public void ShowError(string message, params object[] args) { /* do something */ } /// void ShowError(string message, params object[] args) { /* do something */ }
/// public void Foo() { ///
/// void Foo() {
/// ShowError("Failed: {0}"); // Warning: Non-existing argument in format string /// ShowError("Failed: {0}"); // Warning: Non-existing argument in format string
/// } /// }
/// </code></example> /// </code></example>
@ -76,22 +105,24 @@ namespace Filtration.ObjectModel.Annotations
/// <param name="formatParameterName"> /// <param name="formatParameterName">
/// Specifies which parameter of an annotated method should be treated as format-string /// Specifies which parameter of an annotated method should be treated as format-string
/// </param> /// </param>
public StringFormatMethodAttribute(string formatParameterName) public StringFormatMethodAttribute([NotNull] string formatParameterName)
{ {
FormatParameterName = formatParameterName; FormatParameterName = formatParameterName;
} }
public string FormatParameterName { get; private set; } [NotNull] public string FormatParameterName { get; private set; }
} }
/// <summary> /// <summary>
/// For a parameter that is expected to be one of the limited set of values. /// For a parameter that is expected to be one of the limited set of values.
/// Specify fields of which type should be used as values for this parameter. /// Specify fields of which type should be used as values for this parameter.
/// </summary> /// </summary>
[AttributeUsage(AttributeTargets.Parameter | AttributeTargets.Property | AttributeTargets.Field)] [AttributeUsage(
AttributeTargets.Parameter | AttributeTargets.Property | AttributeTargets.Field,
AllowMultiple = true)]
public sealed class ValueProviderAttribute : Attribute public sealed class ValueProviderAttribute : Attribute
{ {
public ValueProviderAttribute(string name) public ValueProviderAttribute([NotNull] string name)
{ {
Name = name; Name = name;
} }
@ -105,7 +136,7 @@ namespace Filtration.ObjectModel.Annotations
/// the parameter of <see cref="System.ArgumentNullException"/>. /// the parameter of <see cref="System.ArgumentNullException"/>.
/// </summary> /// </summary>
/// <example><code> /// <example><code>
/// public void Foo(string param) { /// void Foo(string param) {
/// if (param == null) /// if (param == null)
/// throw new ArgumentNullException("par"); // Warning: Cannot resolve symbol /// throw new ArgumentNullException("par"); // Warning: Cannot resolve symbol
/// } /// }
@ -131,10 +162,12 @@ namespace Filtration.ObjectModel.Annotations
/// <example><code> /// <example><code>
/// public class Foo : INotifyPropertyChanged { /// public class Foo : INotifyPropertyChanged {
/// public event PropertyChangedEventHandler PropertyChanged; /// public event PropertyChangedEventHandler PropertyChanged;
///
/// [NotifyPropertyChangedInvocator] /// [NotifyPropertyChangedInvocator]
/// protected virtual void NotifyChanged(string propertyName) { ... } /// protected virtual void NotifyChanged(string propertyName) { ... }
/// ///
/// private string _name; /// string _name;
///
/// public string Name { /// public string Name {
/// get { return _name; } /// get { return _name; }
/// set { _name = value; NotifyChanged("LastName"); /* Warning */ } /// set { _name = value; NotifyChanged("LastName"); /* Warning */ }
@ -153,12 +186,12 @@ namespace Filtration.ObjectModel.Annotations
public sealed class NotifyPropertyChangedInvocatorAttribute : Attribute public sealed class NotifyPropertyChangedInvocatorAttribute : Attribute
{ {
public NotifyPropertyChangedInvocatorAttribute() { } public NotifyPropertyChangedInvocatorAttribute() { }
public NotifyPropertyChangedInvocatorAttribute(string parameterName) public NotifyPropertyChangedInvocatorAttribute([NotNull] string parameterName)
{ {
ParameterName = parameterName; ParameterName = parameterName;
} }
public string ParameterName { get; private set; } [CanBeNull] public string ParameterName { get; private set; }
} }
/// <summary> /// <summary>
@ -174,15 +207,16 @@ namespace Filtration.ObjectModel.Annotations
/// <item>Value ::= true | false | null | notnull | canbenull</item> /// <item>Value ::= true | false | null | notnull | canbenull</item>
/// </list> /// </list>
/// If method has single input parameter, it's name could be omitted.<br/> /// If method has single input parameter, it's name could be omitted.<br/>
/// Using <c>halt</c> (or <c>void</c>/<c>nothing</c>, which is the same) /// Using <c>halt</c> (or <c>void</c>/<c>nothing</c>, which is the same) for method output
/// for method output means that the methos doesn't return normally.<br/> /// means that the methos doesn't return normally (throws or terminates the process).<br/>
/// <c>canbenull</c> annotation is only applicable for output parameters.<br/> /// Value <c>canbenull</c> is only applicable for output parameters.<br/>
/// You can use multiple <c>[ContractAnnotation]</c> for each FDT row, /// You can use multiple <c>[ContractAnnotation]</c> for each FDT row, or use single attribute
/// or use single attribute with rows separated by semicolon.<br/> /// with rows separated by semicolon. There is no notion of order rows, all rows are checked
/// for applicability and applied per each program state tracked by R# analysis.<br/>
/// </syntax> /// </syntax>
/// <examples><list> /// <examples><list>
/// <item><code> /// <item><code>
/// [ContractAnnotation("=> halt")] /// [ContractAnnotation("=&gt; halt")]
/// public void TerminationMethod() /// public void TerminationMethod()
/// </code></item> /// </code></item>
/// <item><code> /// <item><code>
@ -190,17 +224,17 @@ namespace Filtration.ObjectModel.Annotations
/// public void Assert(bool condition, string text) // regular assertion method /// public void Assert(bool condition, string text) // regular assertion method
/// </code></item> /// </code></item>
/// <item><code> /// <item><code>
/// [ContractAnnotation("s:null => true")] /// [ContractAnnotation("s:null =&gt; true")]
/// public bool IsNullOrEmpty(string s) // string.IsNullOrEmpty() /// public bool IsNullOrEmpty(string s) // string.IsNullOrEmpty()
/// </code></item> /// </code></item>
/// <item><code> /// <item><code>
/// // A method that returns null if the parameter is null, /// // A method that returns null if the parameter is null,
/// // and not null if the parameter is not null /// // and not null if the parameter is not null
/// [ContractAnnotation("null => null; notnull => notnull")] /// [ContractAnnotation("null =&gt; null; notnull =&gt; notnull")]
/// public object Transform(object data) /// public object Transform(object data)
/// </code></item> /// </code></item>
/// <item><code> /// <item><code>
/// [ContractAnnotation("s:null=>false; =>true,result:notnull; =>false, result:null")] /// [ContractAnnotation("=&gt; true, result: notnull; =&gt; false, result: null")]
/// public bool TryParse(string s, out Person result) /// public bool TryParse(string s, out Person result)
/// </code></item> /// </code></item>
/// </list></examples> /// </list></examples>
@ -216,7 +250,8 @@ namespace Filtration.ObjectModel.Annotations
ForceFullStates = forceFullStates; ForceFullStates = forceFullStates;
} }
public string Contract { get; private set; } [NotNull] public string Contract { get; private set; }
public bool ForceFullStates { get; private set; } public bool ForceFullStates { get; private set; }
} }
@ -225,14 +260,15 @@ namespace Filtration.ObjectModel.Annotations
/// </summary> /// </summary>
/// <example><code> /// <example><code>
/// [LocalizationRequiredAttribute(true)] /// [LocalizationRequiredAttribute(true)]
/// public class Foo { /// class Foo {
/// private string str = "my string"; // Warning: Localizable string /// string str = "my string"; // Warning: Localizable string
/// } /// }
/// </code></example> /// </code></example>
[AttributeUsage(AttributeTargets.All)] [AttributeUsage(AttributeTargets.All)]
public sealed class LocalizationRequiredAttribute : Attribute public sealed class LocalizationRequiredAttribute : Attribute
{ {
public LocalizationRequiredAttribute() : this(true) { } public LocalizationRequiredAttribute() : this(true) { }
public LocalizationRequiredAttribute(bool required) public LocalizationRequiredAttribute(bool required)
{ {
Required = required; Required = required;
@ -250,8 +286,9 @@ namespace Filtration.ObjectModel.Annotations
/// <example><code> /// <example><code>
/// [CannotApplyEqualityOperator] /// [CannotApplyEqualityOperator]
/// class NoEquality { } /// class NoEquality { }
///
/// class UsesNoEquality { /// class UsesNoEquality {
/// public void Test() { /// void Test() {
/// var ca1 = new NoEquality(); /// var ca1 = new NoEquality();
/// var ca2 = new NoEquality(); /// var ca2 = new NoEquality();
/// if (ca1 != null) { // OK /// if (ca1 != null) { // OK
@ -269,9 +306,10 @@ namespace Filtration.ObjectModel.Annotations
/// </summary> /// </summary>
/// <example><code> /// <example><code>
/// [BaseTypeRequired(typeof(IComponent)] // Specify requirement /// [BaseTypeRequired(typeof(IComponent)] // Specify requirement
/// public class ComponentAttribute : Attribute { } /// class ComponentAttribute : Attribute { }
///
/// [Component] // ComponentAttribute requires implementing IComponent interface /// [Component] // ComponentAttribute requires implementing IComponent interface
/// public class MyComponent : IComponent { } /// class MyComponent : IComponent { }
/// </code></example> /// </code></example>
[AttributeUsage(AttributeTargets.Class, AllowMultiple = true)] [AttributeUsage(AttributeTargets.Class, AllowMultiple = true)]
[BaseTypeRequired(typeof(Attribute))] [BaseTypeRequired(typeof(Attribute))]
@ -308,6 +346,7 @@ namespace Filtration.ObjectModel.Annotations
} }
public ImplicitUseKindFlags UseKindFlags { get; private set; } public ImplicitUseKindFlags UseKindFlags { get; private set; }
public ImplicitUseTargetFlags TargetFlags { get; private set; } public ImplicitUseTargetFlags TargetFlags { get; private set; }
} }
@ -334,6 +373,7 @@ namespace Filtration.ObjectModel.Annotations
} }
[UsedImplicitly] public ImplicitUseKindFlags UseKindFlags { get; private set; } [UsedImplicitly] public ImplicitUseKindFlags UseKindFlags { get; private set; }
[UsedImplicitly] public ImplicitUseTargetFlags TargetFlags { get; private set; } [UsedImplicitly] public ImplicitUseTargetFlags TargetFlags { get; private set; }
} }
@ -377,12 +417,13 @@ namespace Filtration.ObjectModel.Annotations
public sealed class PublicAPIAttribute : Attribute public sealed class PublicAPIAttribute : Attribute
{ {
public PublicAPIAttribute() { } public PublicAPIAttribute() { }
public PublicAPIAttribute([NotNull] string comment) public PublicAPIAttribute([NotNull] string comment)
{ {
Comment = comment; Comment = comment;
} }
public string Comment { get; private set; } [CanBeNull] public string Comment { get; private set; }
} }
/// <summary> /// <summary>
@ -398,15 +439,51 @@ namespace Filtration.ObjectModel.Annotations
/// The same as <c>System.Diagnostics.Contracts.PureAttribute</c>. /// The same as <c>System.Diagnostics.Contracts.PureAttribute</c>.
/// </summary> /// </summary>
/// <example><code> /// <example><code>
/// [Pure] private int Multiply(int x, int y) { return x * y; } /// [Pure] int Multiply(int x, int y) => x * y;
/// public void Foo() { ///
/// const int a = 2, b = 2; /// void M() {
/// Multiply(a, b); // Waring: Return value of pure method is not used /// Multiply(123, 42); // Waring: Return value of pure method is not used
/// } /// }
/// </code></example> /// </code></example>
[AttributeUsage(AttributeTargets.Method)] [AttributeUsage(AttributeTargets.Method)]
public sealed class PureAttribute : Attribute { } public sealed class PureAttribute : Attribute { }
/// <summary>
/// Indicates that the return value of method invocation must be used.
/// </summary>
[AttributeUsage(AttributeTargets.Method)]
public sealed class MustUseReturnValueAttribute : Attribute
{
public MustUseReturnValueAttribute() { }
public MustUseReturnValueAttribute([NotNull] string justification)
{
Justification = justification;
}
[CanBeNull] public string Justification { get; private set; }
}
/// <summary>
/// Indicates the type member or parameter of some type, that should be used instead of all other ways
/// to get the value that type. This annotation is useful when you have some "context" value evaluated
/// and stored somewhere, meaning that all other ways to get this value must be consolidated with existing one.
/// </summary>
/// <example><code>
/// class Foo {
/// [ProvidesContext] IBarService _barService = ...;
///
/// void ProcessNode(INode node) {
/// DoSomething(node, node.GetGlobalServices().Bar);
/// // ^ Warning: use value of '_barService' field
/// }
/// }
/// </code></example>
[AttributeUsage(
AttributeTargets.Field | AttributeTargets.Property | AttributeTargets.Parameter | AttributeTargets.Method |
AttributeTargets.Class | AttributeTargets.Interface | AttributeTargets.Struct | AttributeTargets.GenericParameter)]
public sealed class ProvidesContextAttribute : Attribute { }
/// <summary> /// <summary>
/// Indicates that a parameter is a path to a file or a folder within a web project. /// Indicates that a parameter is a path to a file or a folder within a web project.
/// Path can be relative or absolute, starting from web root (~). /// Path can be relative or absolute, starting from web root (~).
@ -415,12 +492,13 @@ namespace Filtration.ObjectModel.Annotations
public sealed class PathReferenceAttribute : Attribute public sealed class PathReferenceAttribute : Attribute
{ {
public PathReferenceAttribute() { } public PathReferenceAttribute() { }
public PathReferenceAttribute([PathReference] string basePath)
public PathReferenceAttribute([NotNull, PathReference] string basePath)
{ {
BasePath = basePath; BasePath = basePath;
} }
public string BasePath { get; private set; } [CanBeNull] public string BasePath { get; private set; }
} }
/// <summary> /// <summary>
@ -484,7 +562,7 @@ namespace Filtration.ObjectModel.Annotations
/// Allows specifying a macro that will be executed for a <see cref="SourceTemplateAttribute">source template</see> /// Allows specifying a macro that will be executed for a <see cref="SourceTemplateAttribute">source template</see>
/// parameter when the template is expanded. /// parameter when the template is expanded.
/// </summary> /// </summary>
public string Expression { get; set; } [CanBeNull] public string Expression { get; set; }
/// <summary> /// <summary>
/// Allows specifying which occurrence of the target parameter becomes editable when the template is deployed. /// Allows specifying which occurrence of the target parameter becomes editable when the template is deployed.
@ -500,73 +578,73 @@ namespace Filtration.ObjectModel.Annotations
/// Identifies the target parameter of a <see cref="SourceTemplateAttribute">source template</see> if the /// Identifies the target parameter of a <see cref="SourceTemplateAttribute">source template</see> if the
/// <see cref="MacroAttribute"/> is applied on a template method. /// <see cref="MacroAttribute"/> is applied on a template method.
/// </summary> /// </summary>
public string Target { get; set; } [CanBeNull] public string Target { get; set; }
} }
[AttributeUsage(AttributeTargets.Assembly, AllowMultiple = true)] [AttributeUsage(AttributeTargets.Assembly | AttributeTargets.Field | AttributeTargets.Property, AllowMultiple = true)]
public sealed class AspMvcAreaMasterLocationFormatAttribute : Attribute public sealed class AspMvcAreaMasterLocationFormatAttribute : Attribute
{ {
public AspMvcAreaMasterLocationFormatAttribute(string format) public AspMvcAreaMasterLocationFormatAttribute([NotNull] string format)
{ {
Format = format; Format = format;
} }
public string Format { get; private set; } [NotNull] public string Format { get; private set; }
} }
[AttributeUsage(AttributeTargets.Assembly, AllowMultiple = true)] [AttributeUsage(AttributeTargets.Assembly | AttributeTargets.Field | AttributeTargets.Property, AllowMultiple = true)]
public sealed class AspMvcAreaPartialViewLocationFormatAttribute : Attribute public sealed class AspMvcAreaPartialViewLocationFormatAttribute : Attribute
{ {
public AspMvcAreaPartialViewLocationFormatAttribute(string format) public AspMvcAreaPartialViewLocationFormatAttribute([NotNull] string format)
{ {
Format = format; Format = format;
} }
public string Format { get; private set; } [NotNull] public string Format { get; private set; }
} }
[AttributeUsage(AttributeTargets.Assembly, AllowMultiple = true)] [AttributeUsage(AttributeTargets.Assembly | AttributeTargets.Field | AttributeTargets.Property, AllowMultiple = true)]
public sealed class AspMvcAreaViewLocationFormatAttribute : Attribute public sealed class AspMvcAreaViewLocationFormatAttribute : Attribute
{ {
public AspMvcAreaViewLocationFormatAttribute(string format) public AspMvcAreaViewLocationFormatAttribute([NotNull] string format)
{ {
Format = format; Format = format;
} }
public string Format { get; private set; } [NotNull] public string Format { get; private set; }
} }
[AttributeUsage(AttributeTargets.Assembly, AllowMultiple = true)] [AttributeUsage(AttributeTargets.Assembly | AttributeTargets.Field | AttributeTargets.Property, AllowMultiple = true)]
public sealed class AspMvcMasterLocationFormatAttribute : Attribute public sealed class AspMvcMasterLocationFormatAttribute : Attribute
{ {
public AspMvcMasterLocationFormatAttribute(string format) public AspMvcMasterLocationFormatAttribute([NotNull] string format)
{ {
Format = format; Format = format;
} }
public string Format { get; private set; } [NotNull] public string Format { get; private set; }
} }
[AttributeUsage(AttributeTargets.Assembly, AllowMultiple = true)] [AttributeUsage(AttributeTargets.Assembly | AttributeTargets.Field | AttributeTargets.Property, AllowMultiple = true)]
public sealed class AspMvcPartialViewLocationFormatAttribute : Attribute public sealed class AspMvcPartialViewLocationFormatAttribute : Attribute
{ {
public AspMvcPartialViewLocationFormatAttribute(string format) public AspMvcPartialViewLocationFormatAttribute([NotNull] string format)
{ {
Format = format; Format = format;
} }
public string Format { get; private set; } [NotNull] public string Format { get; private set; }
} }
[AttributeUsage(AttributeTargets.Assembly, AllowMultiple = true)] [AttributeUsage(AttributeTargets.Assembly | AttributeTargets.Field | AttributeTargets.Property, AllowMultiple = true)]
public sealed class AspMvcViewLocationFormatAttribute : Attribute public sealed class AspMvcViewLocationFormatAttribute : Attribute
{ {
public AspMvcViewLocationFormatAttribute(string format) public AspMvcViewLocationFormatAttribute([NotNull] string format)
{ {
Format = format; Format = format;
} }
public string Format { get; private set; } [NotNull] public string Format { get; private set; }
} }
/// <summary> /// <summary>
@ -579,12 +657,13 @@ namespace Filtration.ObjectModel.Annotations
public sealed class AspMvcActionAttribute : Attribute public sealed class AspMvcActionAttribute : Attribute
{ {
public AspMvcActionAttribute() { } public AspMvcActionAttribute() { }
public AspMvcActionAttribute(string anonymousProperty)
public AspMvcActionAttribute([NotNull] string anonymousProperty)
{ {
AnonymousProperty = anonymousProperty; AnonymousProperty = anonymousProperty;
} }
public string AnonymousProperty { get; private set; } [CanBeNull] public string AnonymousProperty { get; private set; }
} }
/// <summary> /// <summary>
@ -596,12 +675,13 @@ namespace Filtration.ObjectModel.Annotations
public sealed class AspMvcAreaAttribute : Attribute public sealed class AspMvcAreaAttribute : Attribute
{ {
public AspMvcAreaAttribute() { } public AspMvcAreaAttribute() { }
public AspMvcAreaAttribute(string anonymousProperty)
public AspMvcAreaAttribute([NotNull] string anonymousProperty)
{ {
AnonymousProperty = anonymousProperty; AnonymousProperty = anonymousProperty;
} }
public string AnonymousProperty { get; private set; } [CanBeNull] public string AnonymousProperty { get; private set; }
} }
/// <summary> /// <summary>
@ -614,12 +694,13 @@ namespace Filtration.ObjectModel.Annotations
public sealed class AspMvcControllerAttribute : Attribute public sealed class AspMvcControllerAttribute : Attribute
{ {
public AspMvcControllerAttribute() { } public AspMvcControllerAttribute() { }
public AspMvcControllerAttribute(string anonymousProperty)
public AspMvcControllerAttribute([NotNull] string anonymousProperty)
{ {
AnonymousProperty = anonymousProperty; AnonymousProperty = anonymousProperty;
} }
public string AnonymousProperty { get; private set; } [CanBeNull] public string AnonymousProperty { get; private set; }
} }
/// <summary> /// <summary>
@ -649,7 +730,7 @@ namespace Filtration.ObjectModel.Annotations
/// ASP.NET MVC attribute. Allows disabling inspections for MVC views within a class or a method. /// ASP.NET MVC attribute. Allows disabling inspections for MVC views within a class or a method.
/// </summary> /// </summary>
[AttributeUsage(AttributeTargets.Class | AttributeTargets.Method)] [AttributeUsage(AttributeTargets.Class | AttributeTargets.Method)]
public sealed class AspMvcSupressViewErrorAttribute : Attribute { } public sealed class AspMvcSuppressViewErrorAttribute : Attribute { }
/// <summary> /// <summary>
/// ASP.NET MVC attribute. Indicates that a parameter is an MVC display template. /// ASP.NET MVC attribute. Indicates that a parameter is an MVC display template.
@ -677,13 +758,27 @@ namespace Filtration.ObjectModel.Annotations
/// <summary> /// <summary>
/// ASP.NET MVC attribute. If applied to a parameter, indicates that the parameter /// ASP.NET MVC attribute. If applied to a parameter, indicates that the parameter
/// is an MVC view. If applied to a method, the MVC view name is calculated implicitly /// is an MVC view component. If applied to a method, the MVC view name is calculated implicitly
/// from the context. Use this attribute for custom wrappers similar to /// from the context. Use this attribute for custom wrappers similar to
/// <c>System.Web.Mvc.Controller.View(Object)</c>. /// <c>System.Web.Mvc.Controller.View(Object)</c>.
/// </summary> /// </summary>
[AttributeUsage(AttributeTargets.Parameter | AttributeTargets.Method)] [AttributeUsage(AttributeTargets.Parameter | AttributeTargets.Method)]
public sealed class AspMvcViewAttribute : Attribute { } public sealed class AspMvcViewAttribute : Attribute { }
/// <summary>
/// ASP.NET MVC attribute. If applied to a parameter, indicates that the parameter
/// is an MVC view component name.
/// </summary>
[AttributeUsage(AttributeTargets.Parameter)]
public sealed class AspMvcViewComponentAttribute : Attribute { }
/// <summary>
/// ASP.NET MVC attribute. If applied to a parameter, indicates that the parameter
/// is an MVC view component view. If applied to a method, the MVC view component view name is default.
/// </summary>
[AttributeUsage(AttributeTargets.Parameter | AttributeTargets.Method)]
public sealed class AspMvcViewComponentViewAttribute : Attribute { }
/// <summary> /// <summary>
/// ASP.NET MVC attribute. When applied to a parameter of an attribute, /// ASP.NET MVC attribute. When applied to a parameter of an attribute,
/// indicates that this parameter is an MVC action name. /// indicates that this parameter is an MVC action name.
@ -702,12 +797,13 @@ namespace Filtration.ObjectModel.Annotations
public sealed class HtmlElementAttributesAttribute : Attribute public sealed class HtmlElementAttributesAttribute : Attribute
{ {
public HtmlElementAttributesAttribute() { } public HtmlElementAttributesAttribute() { }
public HtmlElementAttributesAttribute(string name)
public HtmlElementAttributesAttribute([NotNull] string name)
{ {
Name = name; Name = name;
} }
public string Name { get; private set; } [CanBeNull] public string Name { get; private set; }
} }
[AttributeUsage(AttributeTargets.Parameter | AttributeTargets.Field | AttributeTargets.Property)] [AttributeUsage(AttributeTargets.Parameter | AttributeTargets.Field | AttributeTargets.Property)]
@ -730,9 +826,10 @@ namespace Filtration.ObjectModel.Annotations
public sealed class RazorSectionAttribute : Attribute { } public sealed class RazorSectionAttribute : Attribute { }
/// <summary> /// <summary>
/// Indicates how method invocation affects content of the collection. /// Indicates how method, constructor invocation or property access
/// over collection type affects content of the collection.
/// </summary> /// </summary>
[AttributeUsage(AttributeTargets.Method)] [AttributeUsage(AttributeTargets.Method | AttributeTargets.Constructor | AttributeTargets.Property)]
public sealed class CollectionAccessAttribute : Attribute public sealed class CollectionAccessAttribute : Attribute
{ {
public CollectionAccessAttribute(CollectionAccessType collectionAccessType) public CollectionAccessAttribute(CollectionAccessType collectionAccessType)
@ -824,6 +921,16 @@ namespace Filtration.ObjectModel.Annotations
[AttributeUsage(AttributeTargets.Parameter)] [AttributeUsage(AttributeTargets.Parameter)]
public sealed class RegexPatternAttribute : Attribute { } public sealed class RegexPatternAttribute : Attribute { }
/// <summary>
/// Prevents the Member Reordering feature from tossing members of the marked class.
/// </summary>
/// <remarks>
/// The attribute must be mentioned in your member reordering patterns
/// </remarks>
[AttributeUsage(
AttributeTargets.Class | AttributeTargets.Interface | AttributeTargets.Struct | AttributeTargets.Enum)]
public sealed class NoReorderAttribute : Attribute { }
/// <summary> /// <summary>
/// XAML attribute. Indicates the type that has <c>ItemsSource</c> property and should be treated /// XAML attribute. Indicates the type that has <c>ItemsSource</c> property and should be treated
/// as <c>ItemsControl</c>-derived type, to enable inner items <c>DataContext</c> type resolve. /// as <c>ItemsControl</c>-derived type, to enable inner items <c>DataContext</c> type resolve.
@ -832,7 +939,7 @@ namespace Filtration.ObjectModel.Annotations
public sealed class XamlItemsControlAttribute : Attribute { } public sealed class XamlItemsControlAttribute : Attribute { }
/// <summary> /// <summary>
/// XAML attibute. Indicates the property of some <c>BindingBase</c>-derived type, that /// XAML attribute. Indicates the property of some <c>BindingBase</c>-derived type, that
/// is used to bind some item of <c>ItemsControl</c>-derived type. This annotation will /// is used to bind some item of <c>ItemsControl</c>-derived type. This annotation will
/// enable the <c>DataContext</c> type resolve for XAML bindings for such properties. /// enable the <c>DataContext</c> type resolve for XAML bindings for such properties.
/// </summary> /// </summary>
@ -846,14 +953,15 @@ namespace Filtration.ObjectModel.Annotations
[AttributeUsage(AttributeTargets.Class, AllowMultiple = true)] [AttributeUsage(AttributeTargets.Class, AllowMultiple = true)]
public sealed class AspChildControlTypeAttribute : Attribute public sealed class AspChildControlTypeAttribute : Attribute
{ {
public AspChildControlTypeAttribute(string tagName, Type controlType) public AspChildControlTypeAttribute([NotNull] string tagName, [NotNull] Type controlType)
{ {
TagName = tagName; TagName = tagName;
ControlType = controlType; ControlType = controlType;
} }
public string TagName { get; private set; } [NotNull] public string TagName { get; private set; }
public Type ControlType { get; private set; }
[NotNull] public Type ControlType { get; private set; }
} }
[AttributeUsage(AttributeTargets.Property | AttributeTargets.Method)] [AttributeUsage(AttributeTargets.Property | AttributeTargets.Method)]
@ -873,7 +981,7 @@ namespace Filtration.ObjectModel.Annotations
Attribute = attribute; Attribute = attribute;
} }
public string Attribute { get; private set; } [NotNull] public string Attribute { get; private set; }
} }
[AttributeUsage(AttributeTargets.Property)] [AttributeUsage(AttributeTargets.Property)]
@ -890,25 +998,37 @@ namespace Filtration.ObjectModel.Annotations
[AttributeUsage(AttributeTargets.Assembly, AllowMultiple = true)] [AttributeUsage(AttributeTargets.Assembly, AllowMultiple = true)]
public sealed class RazorImportNamespaceAttribute : Attribute public sealed class RazorImportNamespaceAttribute : Attribute
{ {
public RazorImportNamespaceAttribute(string name) public RazorImportNamespaceAttribute([NotNull] string name)
{ {
Name = name; Name = name;
} }
public string Name { get; private set; } [NotNull] public string Name { get; private set; }
} }
[AttributeUsage(AttributeTargets.Assembly, AllowMultiple = true)] [AttributeUsage(AttributeTargets.Assembly, AllowMultiple = true)]
public sealed class RazorInjectionAttribute : Attribute public sealed class RazorInjectionAttribute : Attribute
{ {
public RazorInjectionAttribute(string type, string fieldName) public RazorInjectionAttribute([NotNull] string type, [NotNull] string fieldName)
{ {
Type = type; Type = type;
FieldName = fieldName; FieldName = fieldName;
} }
public string Type { get; private set; } [NotNull] public string Type { get; private set; }
public string FieldName { get; private set; }
[NotNull] public string FieldName { get; private set; }
}
[AttributeUsage(AttributeTargets.Assembly, AllowMultiple = true)]
public sealed class RazorDirectiveAttribute : Attribute
{
public RazorDirectiveAttribute([NotNull] string directive)
{
Directive = directive;
}
[NotNull] public string Directive { get; private set; }
} }
[AttributeUsage(AttributeTargets.Method)] [AttributeUsage(AttributeTargets.Method)]
@ -925,13 +1045,4 @@ namespace Filtration.ObjectModel.Annotations
[AttributeUsage(AttributeTargets.Parameter)] [AttributeUsage(AttributeTargets.Parameter)]
public sealed class RazorWriteMethodParameterAttribute : Attribute { } public sealed class RazorWriteMethodParameterAttribute : Attribute { }
/// <summary>
/// Prevents the Member Reordering feature from tossing members of the marked class.
/// </summary>
/// <remarks>
/// The attribute must be mentioned in your member reordering patterns
/// </remarks>
[AttributeUsage(AttributeTargets.All)]
public sealed class NoReorder : Attribute { }
} }

View File

@ -1,4 +1,5 @@
using System.Reflection; using System.Reflection;
using System.Runtime.CompilerServices;
using System.Runtime.InteropServices; using System.Runtime.InteropServices;
// General Information about an assembly is controlled through the following // General Information about an assembly is controlled through the following
@ -33,3 +34,9 @@ using System.Runtime.InteropServices;
// [assembly: AssemblyVersion("1.0.*")] // [assembly: AssemblyVersion("1.0.*")]
[assembly: AssemblyVersion("1.0.0.0")] [assembly: AssemblyVersion("1.0.0.0")]
[assembly: AssemblyFileVersion("1.0.0.0")] [assembly: AssemblyFileVersion("1.0.0.0")]
[assembly: InternalsVisibleTo("Filtration.ItemFilterPreview.Tests")]
[assembly: InternalsVisibleTo("Filtration.ObjectModel.Tests")]
[assembly: InternalsVisibleTo("Filtration.Parser.Tests")]
[assembly: InternalsVisibleTo("Filtration.Tests")]
[assembly: InternalsVisibleTo("Filtration.ThemeEditor.Tests")]

View File

@ -0,0 +1,21 @@
using Castle.MicroKernel.Registration;
using Castle.MicroKernel.SubSystems.Configuration;
using Castle.Windsor;
using Filtration.ObjectModel.Commands;
namespace Filtration.ObjectModel.WindsorInstallers
{
public class CommandsInstaller : IWindsorInstaller
{
public void Install(IWindsorContainer container, IConfigurationStore store)
{
container.Register(Component
.For<ICommandManager>()
.Forward<ICommandManagerInternal>()
.ImplementedBy<CommandManager>()
.LifestyleTransient());
}
}
}

View File

@ -0,0 +1,23 @@
using Castle.Facilities.TypedFactory;
using Castle.MicroKernel.Registration;
using Castle.MicroKernel.SubSystems.Configuration;
using Castle.Windsor;
using Filtration.ObjectModel.Factories;
namespace Filtration.ObjectModel.WindsorInstallers
{
public class ModelsInstaller : IWindsorInstaller
{
public void Install(IWindsorContainer container, IConfigurationStore store)
{
container.Register(Component
.For<IItemFilterScript>()
.ImplementedBy<ItemFilterScript>()
.LifestyleTransient());
container.Register(Component
.For<IItemFilterScriptFactory>()
.AsFactory());
}
}
}

View File

@ -0,0 +1,5 @@
<?xml version="1.0" encoding="utf-8"?>
<packages>
<package id="Castle.Core" version="3.3.0" targetFramework="net461" />
<package id="Castle.Windsor" version="3.4.0" targetFramework="net461" />
</packages>

View File

@ -4,7 +4,7 @@ namespace Filtration.Parser.Interface.Services
{ {
public interface IItemFilterScriptTranslator public interface IItemFilterScriptTranslator
{ {
ItemFilterScript TranslateStringToItemFilterScript(string inputString); IItemFilterScript TranslateStringToItemFilterScript(string inputString);
string TranslateItemFilterScriptToString(ItemFilterScript script); string TranslateItemFilterScriptToString(IItemFilterScript script);
} }
} }

View File

@ -5,6 +5,7 @@ using System.Linq;
using Filtration.ObjectModel; using Filtration.ObjectModel;
using Filtration.ObjectModel.BlockItemTypes; using Filtration.ObjectModel.BlockItemTypes;
using Filtration.ObjectModel.Enums; using Filtration.ObjectModel.Enums;
using Filtration.ObjectModel.Factories;
using Filtration.ObjectModel.ThemeEditor; using Filtration.ObjectModel.ThemeEditor;
using Filtration.Parser.Interface.Services; using Filtration.Parser.Interface.Services;
using Filtration.Parser.Services; using Filtration.Parser.Services;
@ -19,12 +20,9 @@ namespace Filtration.Parser.Tests.Services
[TestFixture] [TestFixture]
public class TestItemFilterScriptTranslator public class TestItemFilterScriptTranslator
{ {
private ItemFilterScriptTranslatorTestUtility _testUtility;
[SetUp] [SetUp]
public void ItemFilterScriptTranslatorTestSetup() public void ItemFilterScriptTranslatorTestSetup()
{ {
_testUtility = new ItemFilterScriptTranslatorTestUtility();
Settings.Default.Reset(); Settings.Default.Reset();
} }
@ -33,13 +31,16 @@ namespace Filtration.Parser.Tests.Services
{ {
// Arrange // Arrange
var testInput = Resources.testscript; var testInput = Resources.testscript;
var mockItemFilterBlockTranslator = new Mock<IItemFilterBlockTranslator>();
var translator = CreateItemFilterScriptTranslator(itemFilterBlockTranslator: mockItemFilterBlockTranslator.Object);
// Act // Act
var script = _testUtility.ScriptTranslator.TranslateStringToItemFilterScript(testInput); var script = translator.TranslateStringToItemFilterScript(testInput);
// Assert // Assert
Assert.AreEqual(5, script.ItemFilterBlocks.Count); Assert.AreEqual(5, script.ItemFilterBlocks.Count);
_testUtility.MockItemFilterBlockTranslator.Verify(t => t.TranslateStringToItemFilterBlock(It.IsAny<string>(), It.IsAny<IItemFilterScriptSettings>())); mockItemFilterBlockTranslator.Verify(t => t.TranslateStringToItemFilterBlock(It.IsAny<string>(), It.IsAny<IItemFilterScriptSettings>()));
} }
[Test] [Test]
@ -54,8 +55,10 @@ namespace Filtration.Parser.Tests.Services
Environment.NewLine + Environment.NewLine +
"End Script Description"; "End Script Description";
var translator = CreateItemFilterScriptTranslator();
// Act // Act
var script = _testUtility.ScriptTranslator.TranslateStringToItemFilterScript(testInput); var script = translator.TranslateStringToItemFilterScript(testInput);
// Assert // Assert
Assert.AreEqual(expectedDescription, script.Description); Assert.AreEqual(expectedDescription, script.Description);
@ -67,8 +70,8 @@ namespace Filtration.Parser.Tests.Services
// Arrange // Arrange
var testInput = Resources.ThioleItemFilter; var testInput = Resources.ThioleItemFilter;
var blockTranslator = new ItemFilterBlockTranslator(_testUtility.MockBlockGroupHierarchyBuilder.Object); var blockTranslator = new ItemFilterBlockTranslator(Mock.Of<IBlockGroupHierarchyBuilder>());
var translator = new ItemFilterScriptTranslator(blockTranslator, _testUtility.MockBlockGroupHierarchyBuilder.Object); var translator = CreateItemFilterScriptTranslator(itemFilterBlockTranslator: blockTranslator);
// Act // Act
translator.TranslateStringToItemFilterScript(testInput); translator.TranslateStringToItemFilterScript(testInput);
@ -83,9 +86,9 @@ namespace Filtration.Parser.Tests.Services
// Arrange // Arrange
var testInput = Resources.testscript2; var testInput = Resources.testscript2;
var blockTranslator = new ItemFilterBlockTranslator(_testUtility.MockBlockGroupHierarchyBuilder.Object); var blockTranslator = new ItemFilterBlockTranslator(Mock.Of<IBlockGroupHierarchyBuilder>());
var translator = new ItemFilterScriptTranslator(blockTranslator, _testUtility.MockBlockGroupHierarchyBuilder.Object); var translator = CreateItemFilterScriptTranslator(itemFilterBlockTranslator: blockTranslator);
// Act // Act
var result = translator.TranslateStringToItemFilterScript(testInput); var result = translator.TranslateStringToItemFilterScript(testInput);
@ -119,15 +122,20 @@ namespace Filtration.Parser.Tests.Services
const string blockOutput = "Test Script Output"; const string blockOutput = "Test Script Output";
testScript.ItemFilterBlocks.Add(testBlock); testScript.ItemFilterBlocks.Add(testBlock);
var mockItemFilterBlockTranslator = new Mock<IItemFilterBlockTranslator>();
mockItemFilterBlockTranslator
.Setup(t => t.TranslateItemFilterBlockToString(testBlock))
.Returns(blockOutput)
.Verifiable();
_testUtility.MockItemFilterBlockTranslator.Setup(t => t.TranslateItemFilterBlockToString(testBlock)).Returns(blockOutput).Verifiable(); var translator = CreateItemFilterScriptTranslator(itemFilterBlockTranslator: mockItemFilterBlockTranslator.Object);
// Act // Act
_testUtility.ScriptTranslator.TranslateItemFilterScriptToString(testScript); translator.TranslateItemFilterScriptToString(testScript);
// Assert // Assert
_testUtility.MockItemFilterBlockTranslator.Verify(); mockItemFilterBlockTranslator.Verify();
} }
[Test] [Test]
@ -156,9 +164,8 @@ namespace Filtration.Parser.Tests.Services
" Width = 3" + Environment.NewLine + " Width = 3" + Environment.NewLine +
" SetFontSize 7" + Environment.NewLine; " SetFontSize 7" + Environment.NewLine;
var blockTranslator = new ItemFilterBlockTranslator(_testUtility.MockBlockGroupHierarchyBuilder.Object); var blockTranslator = new ItemFilterBlockTranslator(Mock.Of<IBlockGroupHierarchyBuilder>());
var translator = new ItemFilterScriptTranslator(blockTranslator, var translator = CreateItemFilterScriptTranslator(itemFilterBlockTranslator: blockTranslator);
_testUtility.MockBlockGroupHierarchyBuilder.Object);
// Act // Act
var result = translator.TranslateItemFilterScriptToString(script); var result = translator.TranslateItemFilterScriptToString(script);
@ -201,9 +208,8 @@ namespace Filtration.Parser.Tests.Services
" Width = 3" + Environment.NewLine + " Width = 3" + Environment.NewLine +
" SetFontSize 7" + Environment.NewLine + Environment.NewLine; " SetFontSize 7" + Environment.NewLine + Environment.NewLine;
var blockTranslator = new ItemFilterBlockTranslator(_testUtility.MockBlockGroupHierarchyBuilder.Object); var blockTranslator = new ItemFilterBlockTranslator(Mock.Of<IBlockGroupHierarchyBuilder>());
var translator = new ItemFilterScriptTranslator(blockTranslator, var translator = CreateItemFilterScriptTranslator(itemFilterBlockTranslator: blockTranslator);
_testUtility.MockBlockGroupHierarchyBuilder.Object);
// Act // Act
var result = translator.TranslateItemFilterScriptToString(script); var result = translator.TranslateItemFilterScriptToString(script);
@ -225,8 +231,10 @@ namespace Filtration.Parser.Tests.Services
Environment.NewLine + Environment.NewLine +
"# Test script description" + Environment.NewLine + Environment.NewLine; "# Test script description" + Environment.NewLine + Environment.NewLine;
var translator = CreateItemFilterScriptTranslator();
// Act // Act
var result = _testUtility.ScriptTranslator.TranslateItemFilterScriptToString(script); var result = translator.TranslateItemFilterScriptToString(script);
// Assert // Assert
Assert.AreEqual(expectedOutput, result); Assert.AreEqual(expectedOutput, result);
@ -240,9 +248,8 @@ namespace Filtration.Parser.Tests.Services
Environment.NewLine + Environment.NewLine +
"Show" + Environment.NewLine + "Show" + Environment.NewLine +
"BaseType \"Maelström Staff\"" + Environment.NewLine + Environment.NewLine; "BaseType \"Maelström Staff\"" + Environment.NewLine + Environment.NewLine;
var blockTranslator = new ItemFilterBlockTranslator(_testUtility.MockBlockGroupHierarchyBuilder.Object); var blockTranslator = new ItemFilterBlockTranslator(Mock.Of<IBlockGroupHierarchyBuilder>());
var translator = new ItemFilterScriptTranslator(blockTranslator, var translator = CreateItemFilterScriptTranslator(itemFilterBlockTranslator: blockTranslator);
_testUtility.MockBlockGroupHierarchyBuilder.Object);
// Act // Act
var result = translator.TranslateStringToItemFilterScript(testInputScript); var result = translator.TranslateStringToItemFilterScript(testInputScript);
@ -274,9 +281,8 @@ namespace Filtration.Parser.Tests.Services
" SetTextColor 255 255 0"; " SetTextColor 255 255 0";
var blockTranslator = new ItemFilterBlockTranslator(_testUtility.MockBlockGroupHierarchyBuilder.Object); var blockTranslator = new ItemFilterBlockTranslator(Mock.Of<IBlockGroupHierarchyBuilder>());
var translator = new ItemFilterScriptTranslator(blockTranslator, var translator = CreateItemFilterScriptTranslator(itemFilterBlockTranslator: blockTranslator);
_testUtility.MockBlockGroupHierarchyBuilder.Object);
// Act // Act
var result = translator.TranslateStringToItemFilterScript(testInputScript); var result = translator.TranslateStringToItemFilterScript(testInputScript);
@ -306,9 +312,8 @@ namespace Filtration.Parser.Tests.Services
" SetTextColor 255 255 0"; " SetTextColor 255 255 0";
var blockTranslator = new ItemFilterBlockTranslator(_testUtility.MockBlockGroupHierarchyBuilder.Object); var blockTranslator = new ItemFilterBlockTranslator(Mock.Of<IBlockGroupHierarchyBuilder>());
var translator = new ItemFilterScriptTranslator(blockTranslator, var translator = CreateItemFilterScriptTranslator(itemFilterBlockTranslator: blockTranslator);
_testUtility.MockBlockGroupHierarchyBuilder.Object);
// Act // Act
var result = translator.TranslateStringToItemFilterScript(testInputScript); var result = translator.TranslateStringToItemFilterScript(testInputScript);
@ -340,9 +345,8 @@ namespace Filtration.Parser.Tests.Services
"#Disabled Block End"; "#Disabled Block End";
var blockTranslator = new ItemFilterBlockTranslator(_testUtility.MockBlockGroupHierarchyBuilder.Object); var blockTranslator = new ItemFilterBlockTranslator(Mock.Of<IBlockGroupHierarchyBuilder>());
var translator = new ItemFilterScriptTranslator(blockTranslator, var translator = CreateItemFilterScriptTranslator(itemFilterBlockTranslator: blockTranslator);
_testUtility.MockBlockGroupHierarchyBuilder.Object);
// Act // Act
var result = translator.TranslateStringToItemFilterScript(testInputScript); var result = translator.TranslateStringToItemFilterScript(testInputScript);
@ -370,14 +374,14 @@ namespace Filtration.Parser.Tests.Services
"#Disabled Block End"; "#Disabled Block End";
var mockBlockGroupHierarchyBuilder = new Mock<IBlockGroupHierarchyBuilder>();
var blockTranslator = new ItemFilterBlockTranslator(_testUtility.MockBlockGroupHierarchyBuilder.Object); mockBlockGroupHierarchyBuilder.Setup(
_testUtility.MockBlockGroupHierarchyBuilder.Setup( b => b.IntegrateStringListIntoBlockGroupHierarchy(It.IsAny<IEnumerable<string>>()))
b => b.IntegrateStringListIntoBlockGroupHierarchy(It.IsAny<IEnumerable<string>>()))
.Returns(new ItemFilterBlockGroup("My Block Group", null)); .Returns(new ItemFilterBlockGroup("My Block Group", null));
var translator = new ItemFilterScriptTranslator(blockTranslator, var blockTranslator = new ItemFilterBlockTranslator(mockBlockGroupHierarchyBuilder.Object);
_testUtility.MockBlockGroupHierarchyBuilder.Object);
var translator = CreateItemFilterScriptTranslator(itemFilterBlockTranslator: blockTranslator);
// Act // Act
var result = translator.TranslateStringToItemFilterScript(testInputScript); var result = translator.TranslateStringToItemFilterScript(testInputScript);
@ -389,21 +393,18 @@ namespace Filtration.Parser.Tests.Services
Assert.AreEqual("My Block Group", secondBlock.BlockGroup.GroupName); Assert.AreEqual("My Block Group", secondBlock.BlockGroup.GroupName);
} }
private class ItemFilterScriptTranslatorTestUtility private ItemFilterScriptTranslator CreateItemFilterScriptTranslator(IBlockGroupHierarchyBuilder blockGroupHierarchyBuilder = null,
IItemFilterBlockTranslator itemFilterBlockTranslator = null,
IItemFilterScriptFactory itemFilterScriptFactory = null)
{ {
public ItemFilterScriptTranslatorTestUtility() var mockItemFilterScriptFactory = new Mock<IItemFilterScriptFactory>();
{ mockItemFilterScriptFactory
// Mock setups .Setup(i => i.Create())
MockItemFilterBlockTranslator = new Mock<IItemFilterBlockTranslator>(); .Returns(new ItemFilterScript());
MockBlockGroupHierarchyBuilder = new Mock<IBlockGroupHierarchyBuilder>();
// Class under test instantiation return new ItemFilterScriptTranslator(blockGroupHierarchyBuilder ?? new Mock<IBlockGroupHierarchyBuilder>().Object,
ScriptTranslator = new ItemFilterScriptTranslator(MockItemFilterBlockTranslator.Object, MockBlockGroupHierarchyBuilder.Object); itemFilterBlockTranslator ?? new Mock<IItemFilterBlockTranslator>().Object,
} itemFilterScriptFactory ?? mockItemFilterScriptFactory.Object);
public ItemFilterScriptTranslator ScriptTranslator { get; }
public Mock<IItemFilterBlockTranslator> MockItemFilterBlockTranslator { get; }
public Mock<IBlockGroupHierarchyBuilder> MockBlockGroupHierarchyBuilder { get; }
} }
} }
} }

View File

@ -6,6 +6,7 @@ using System.Runtime.InteropServices;
using System.Text.RegularExpressions; using System.Text.RegularExpressions;
using Filtration.Common.Utilities; using Filtration.Common.Utilities;
using Filtration.ObjectModel; using Filtration.ObjectModel;
using Filtration.ObjectModel.Factories;
using Filtration.Parser.Interface.Services; using Filtration.Parser.Interface.Services;
using Filtration.Properties; using Filtration.Properties;
@ -35,13 +36,16 @@ namespace Filtration.Parser.Services
internal class ItemFilterScriptTranslator : IItemFilterScriptTranslator internal class ItemFilterScriptTranslator : IItemFilterScriptTranslator
{ {
private readonly IItemFilterBlockTranslator _blockTranslator; private readonly IItemFilterBlockTranslator _blockTranslator;
private readonly IItemFilterScriptFactory _itemFilterScriptFactory;
private readonly IBlockGroupHierarchyBuilder _blockGroupHierarchyBuilder; private readonly IBlockGroupHierarchyBuilder _blockGroupHierarchyBuilder;
public ItemFilterScriptTranslator(IItemFilterBlockTranslator blockTranslator, public ItemFilterScriptTranslator(IBlockGroupHierarchyBuilder blockGroupHierarchyBuilder,
IBlockGroupHierarchyBuilder blockGroupHierarchyBuilder) IItemFilterBlockTranslator blockTranslator,
IItemFilterScriptFactory itemFilterScriptFactory)
{ {
_blockTranslator = blockTranslator;
_blockGroupHierarchyBuilder = blockGroupHierarchyBuilder; _blockGroupHierarchyBuilder = blockGroupHierarchyBuilder;
_blockTranslator = blockTranslator;
_itemFilterScriptFactory = itemFilterScriptFactory;
} }
public static string PreprocessDisabledBlocks(string inputString) public static string PreprocessDisabledBlocks(string inputString)
@ -104,9 +108,9 @@ namespace Filtration.Parser.Services
return lines.Aggregate((c, n) => c + Environment.NewLine + n); return lines.Aggregate((c, n) => c + Environment.NewLine + n);
} }
public ItemFilterScript TranslateStringToItemFilterScript(string inputString) public IItemFilterScript TranslateStringToItemFilterScript(string inputString)
{ {
var script = new ItemFilterScript(); var script = _itemFilterScriptFactory.Create();
_blockGroupHierarchyBuilder.Initialise(script.ItemFilterBlockGroups.First()); _blockGroupHierarchyBuilder.Initialise(script.ItemFilterBlockGroups.First());
inputString = inputString.Replace("\t", ""); inputString = inputString.Replace("\t", "");
@ -224,7 +228,7 @@ namespace Filtration.Parser.Services
return blockBoundaries; return blockBoundaries;
} }
public string TranslateItemFilterScriptToString(ItemFilterScript script) public string TranslateItemFilterScriptToString(IItemFilterScript script)
{ {
var outputString = string.Empty; var outputString = string.Empty;

View File

@ -2,6 +2,7 @@
using System.IO; using System.IO;
using System.Threading.Tasks; using System.Threading.Tasks;
using Filtration.ObjectModel; using Filtration.ObjectModel;
using Filtration.ObjectModel.Factories;
using Filtration.Repositories; using Filtration.Repositories;
using Filtration.Services; using Filtration.Services;
using Filtration.ViewModels; using Filtration.ViewModels;
@ -29,7 +30,8 @@ namespace Filtration.Tests.Repositories
var mockItemFilterScriptViewModelFactory = new Mock<IItemFilterScriptViewModelFactory>(); var mockItemFilterScriptViewModelFactory = new Mock<IItemFilterScriptViewModelFactory>();
mockItemFilterScriptViewModelFactory.Setup(f => f.Create()).Returns(mockItemFilterScriptViewModel.Object); mockItemFilterScriptViewModelFactory.Setup(f => f.Create()).Returns(mockItemFilterScriptViewModel.Object);
var repository = new ItemFilterScriptRepository(mockPersistenceService.Object, mockItemFilterScriptViewModelFactory.Object); var repository = CreateItemFilterScriptRepository(itemFilterPersistenceService: mockPersistenceService.Object,
itemFilterScriptViewModelFactory: mockItemFilterScriptViewModelFactory.Object);
// Act // Act
var result = await repository.LoadScriptFromFileAsync(testInputPath); var result = await repository.LoadScriptFromFileAsync(testInputPath);
@ -50,7 +52,8 @@ namespace Filtration.Tests.Repositories
var mockItemFilterScriptViewModelFactory = new Mock<IItemFilterScriptViewModelFactory>(); var mockItemFilterScriptViewModelFactory = new Mock<IItemFilterScriptViewModelFactory>();
var repository = new ItemFilterScriptRepository(mockPersistenceService.Object, mockItemFilterScriptViewModelFactory.Object); var repository = CreateItemFilterScriptRepository(itemFilterPersistenceService: mockPersistenceService.Object,
itemFilterScriptViewModelFactory: mockItemFilterScriptViewModelFactory.Object);
// Act // Act
Func<Task<IItemFilterScriptViewModel>> result = async () => await repository.LoadScriptFromFileAsync(testInputPath); Func<Task<IItemFilterScriptViewModel>> result = async () => await repository.LoadScriptFromFileAsync(testInputPath);
@ -70,7 +73,8 @@ namespace Filtration.Tests.Repositories
var mockItemFilterScriptViewModelFactory = new Mock<IItemFilterScriptViewModelFactory>(); var mockItemFilterScriptViewModelFactory = new Mock<IItemFilterScriptViewModelFactory>();
var repository = new ItemFilterScriptRepository(mockPersistenceService.Object, mockItemFilterScriptViewModelFactory.Object); var repository = CreateItemFilterScriptRepository(itemFilterPersistenceService: mockPersistenceService.Object,
itemFilterScriptViewModelFactory: mockItemFilterScriptViewModelFactory.Object);
// Act // Act
repository.SetItemFilterScriptDirectory(testInputPath); repository.SetItemFilterScriptDirectory(testInputPath);
@ -90,7 +94,8 @@ namespace Filtration.Tests.Repositories
var mockItemFilterScriptViewModelFactory = new Mock<IItemFilterScriptViewModelFactory>(); var mockItemFilterScriptViewModelFactory = new Mock<IItemFilterScriptViewModelFactory>();
var repository = new ItemFilterScriptRepository(mockPersistenceService.Object, mockItemFilterScriptViewModelFactory.Object); var repository = CreateItemFilterScriptRepository(itemFilterPersistenceService: mockPersistenceService.Object,
itemFilterScriptViewModelFactory: mockItemFilterScriptViewModelFactory.Object);
// Act // Act
string result = repository.GetItemFilterScriptDirectory(); string result = repository.GetItemFilterScriptDirectory();
@ -111,13 +116,23 @@ namespace Filtration.Tests.Repositories
var mockItemFilterScriptViewModelFactory = new Mock<IItemFilterScriptViewModelFactory>(); var mockItemFilterScriptViewModelFactory = new Mock<IItemFilterScriptViewModelFactory>();
mockItemFilterScriptViewModelFactory.Setup(f => f.Create()).Returns(mockItemFilterScriptViewModel.Object); mockItemFilterScriptViewModelFactory.Setup(f => f.Create()).Returns(mockItemFilterScriptViewModel.Object);
var repository = new ItemFilterScriptRepository(mockPersistenceService.Object, mockItemFilterScriptViewModelFactory.Object); var repository = CreateItemFilterScriptRepository(itemFilterPersistenceService: mockPersistenceService.Object,
itemFilterScriptViewModelFactory: mockItemFilterScriptViewModelFactory.Object);
// Act // Act
IItemFilterScriptViewModel result = repository.NewScript(); IItemFilterScriptViewModel result = repository.NewScript();
// Assert // Assert
Assert.AreEqual(mockItemFilterScriptViewModel.Object, result); Assert.AreEqual(mockItemFilterScriptViewModel.Object, result);
} }
private ItemFilterScriptRepository CreateItemFilterScriptRepository(IItemFilterPersistenceService itemFilterPersistenceService = null,
IItemFilterScriptFactory itemFilterScriptFactory = null,
IItemFilterScriptViewModelFactory itemFilterScriptViewModelFactory = null)
{
return new ItemFilterScriptRepository(itemFilterPersistenceService ?? new Mock<IItemFilterPersistenceService>().Object,
itemFilterScriptFactory ?? new Mock<IItemFilterScriptFactory>().Object,
itemFilterScriptViewModelFactory ?? new Mock<IItemFilterScriptViewModelFactory>().Object);
}
} }
} }

View File

@ -11,8 +11,8 @@ namespace Filtration.ThemeEditor.Providers
{ {
public interface IThemeProvider public interface IThemeProvider
{ {
IThemeEditorViewModel NewThemeForScript(ItemFilterScript script); IThemeEditorViewModel NewThemeForScript(IItemFilterScript script);
IThemeEditorViewModel MasterThemeForScript(ItemFilterScript script); IThemeEditorViewModel MasterThemeForScript(IItemFilterScript script);
Task<IThemeEditorViewModel> LoadThemeFromFile(string filePath); Task<IThemeEditorViewModel> LoadThemeFromFile(string filePath);
Task<Theme> LoadThemeModelFromFile(string filePath); Task<Theme> LoadThemeModelFromFile(string filePath);
Task SaveThemeAsync(IThemeEditorViewModel themeEditorViewModel, string filePath); Task SaveThemeAsync(IThemeEditorViewModel themeEditorViewModel, string filePath);
@ -29,7 +29,7 @@ namespace Filtration.ThemeEditor.Providers
_themePersistenceService = themePersistenceService; _themePersistenceService = themePersistenceService;
} }
public IThemeEditorViewModel NewThemeForScript(ItemFilterScript script) public IThemeEditorViewModel NewThemeForScript(IItemFilterScript script)
{ {
var themeComponentCollection = script.ThemeComponents.Aggregate(new ThemeComponentCollection(), var themeComponentCollection = script.ThemeComponents.Aggregate(new ThemeComponentCollection(),
(c, component) => (c, component) =>
@ -45,7 +45,7 @@ namespace Filtration.ThemeEditor.Providers
return themeViewModel; return themeViewModel;
} }
public IThemeEditorViewModel MasterThemeForScript(ItemFilterScript script) public IThemeEditorViewModel MasterThemeForScript(IItemFilterScript script)
{ {
var themeViewModel = _themeViewModelFactory.Create(); var themeViewModel = _themeViewModelFactory.Create();
themeViewModel.InitialiseForMasterTheme(script); themeViewModel.InitialiseForMasterTheme(script);

View File

@ -12,7 +12,7 @@ namespace Filtration.ThemeEditor.Services
{ {
public interface IThemeService public interface IThemeService
{ {
void ApplyThemeToScript(Theme theme, ItemFilterScript script); void ApplyThemeToScript(Theme theme, IItemFilterScript script);
} }
public class ThemeService : IThemeService public class ThemeService : IThemeService
@ -24,7 +24,7 @@ namespace Filtration.ThemeEditor.Services
_messageBoxService = messageBoxService; _messageBoxService = messageBoxService;
} }
public void ApplyThemeToScript(Theme theme, ItemFilterScript script) public void ApplyThemeToScript(Theme theme, IItemFilterScript script)
{ {
var mismatchedComponents = false; var mismatchedComponents = false;
foreach (var component in theme.Components) foreach (var component in theme.Components)

View File

@ -26,9 +26,9 @@ namespace Filtration.ThemeEditor.ViewModels
RelayCommand CloseCommand { get; } RelayCommand CloseCommand { get; }
void InitialiseForNewTheme(ThemeComponentCollection themeComponentCollection); void InitialiseForNewTheme(ThemeComponentCollection themeComponentCollection);
void InitialiseForMasterTheme(ItemFilterScript script); void InitialiseForMasterTheme(IItemFilterScript script);
bool IsMasterTheme { get; } bool IsMasterTheme { get; }
ItemFilterScript IsMasterThemeForScript { get; } IItemFilterScript IsMasterThemeForScript { get; }
string Title { get; } string Title { get; }
string FilePath { get; set; } string FilePath { get; set; }
string Filename { get; } string Filename { get; }
@ -72,7 +72,7 @@ namespace Filtration.ThemeEditor.ViewModels
public bool IsMasterTheme => Components.IsMasterCollection; public bool IsMasterTheme => Components.IsMasterCollection;
public ItemFilterScript IsMasterThemeForScript { get; private set; } public IItemFilterScript IsMasterThemeForScript { get; private set; }
public void InitialiseForNewTheme(ThemeComponentCollection themeComponentCollection) public void InitialiseForNewTheme(ThemeComponentCollection themeComponentCollection)
{ {
@ -80,7 +80,7 @@ namespace Filtration.ThemeEditor.ViewModels
_filenameIsFake = true; _filenameIsFake = true;
} }
public void InitialiseForMasterTheme(ItemFilterScript script) public void InitialiseForMasterTheme(IItemFilterScript script)
{ {
Components = script.ThemeComponents; Components = script.ThemeComponents;
IsMasterThemeForScript = script; IsMasterThemeForScript = script;

View File

@ -1,4 +1,5 @@
<wpf:ResourceDictionary xml:space="preserve" xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" xmlns:s="clr-namespace:System;assembly=mscorlib" xmlns:ss="urn:shemas-jetbrains-com:settings-storage-xaml" xmlns:wpf="http://schemas.microsoft.com/winfx/2006/xaml/presentation"> <wpf:ResourceDictionary xml:space="preserve" xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" xmlns:s="clr-namespace:System;assembly=mscorlib" xmlns:ss="urn:shemas-jetbrains-com:settings-storage-xaml" xmlns:wpf="http://schemas.microsoft.com/winfx/2006/xaml/presentation">
<s:Boolean x:Key="/Default/CodeInspection/CodeAnnotations/NamespacesWithAnnotations/=Filtration_002EAnnotations/@EntryIndexedValue">True</s:Boolean> <s:Boolean x:Key="/Default/CodeInspection/CodeAnnotations/NamespacesWithAnnotations/=Filtration_002EAnnotations/@EntryIndexedValue">True</s:Boolean>
<s:Boolean x:Key="/Default/CodeInspection/CodeAnnotations/NamespacesWithAnnotations/=Filtration_002EObjectModel_002EAnnotations/@EntryIndexedValue">True</s:Boolean>
<s:String x:Key="/Default/FilterSettingsManager/AttributeFilterXml/@EntryValue">&lt;data /&gt;</s:String> <s:String x:Key="/Default/FilterSettingsManager/AttributeFilterXml/@EntryValue">&lt;data /&gt;</s:String>
<s:String x:Key="/Default/FilterSettingsManager/CoverageFilterXml/@EntryValue">&lt;data&gt;&lt;IncludeFilters /&gt;&lt;ExcludeFilters&gt;&lt;Filter ModuleMask="Filtration.ItemFilterPreview.Tests" ModuleVersionMask="*" ClassMask="*" FunctionMask="*" IsEnabled="True" /&gt;&lt;Filter ModuleMask="Filtration.ObjectModel.Tests" ModuleVersionMask="*" ClassMask="*" FunctionMask="*" IsEnabled="True" /&gt;&lt;Filter ModuleMask="Filtration.ThemeEditor.Tests" ModuleVersionMask="*" ClassMask="*" FunctionMask="*" IsEnabled="True" /&gt;&lt;Filter ModuleMask="Filtration.Tests" ModuleVersionMask="*" ClassMask="*" FunctionMask="*" IsEnabled="True" /&gt;&lt;/ExcludeFilters&gt;&lt;/data&gt;</s:String></wpf:ResourceDictionary> <s:String x:Key="/Default/FilterSettingsManager/CoverageFilterXml/@EntryValue">&lt;data&gt;&lt;IncludeFilters /&gt;&lt;ExcludeFilters&gt;&lt;Filter ModuleMask="Filtration.ItemFilterPreview.Tests" ModuleVersionMask="*" ClassMask="*" FunctionMask="*" IsEnabled="True" /&gt;&lt;Filter ModuleMask="Filtration.ObjectModel.Tests" ModuleVersionMask="*" ClassMask="*" FunctionMask="*" IsEnabled="True" /&gt;&lt;Filter ModuleMask="Filtration.ThemeEditor.Tests" ModuleVersionMask="*" ClassMask="*" FunctionMask="*" IsEnabled="True" /&gt;&lt;Filter ModuleMask="Filtration.Tests" ModuleVersionMask="*" ClassMask="*" FunctionMask="*" IsEnabled="True" /&gt;&lt;/ExcludeFilters&gt;&lt;/data&gt;</s:String></wpf:ResourceDictionary>

View File

@ -1,5 +1,6 @@
using System.Threading.Tasks; using System.Threading.Tasks;
using Filtration.ObjectModel; using Filtration.ObjectModel;
using Filtration.ObjectModel.Factories;
using Filtration.Services; using Filtration.Services;
using Filtration.ViewModels; using Filtration.ViewModels;
@ -16,12 +17,15 @@ namespace Filtration.Repositories
internal class ItemFilterScriptRepository : IItemFilterScriptRepository internal class ItemFilterScriptRepository : IItemFilterScriptRepository
{ {
private readonly IItemFilterPersistenceService _itemFilterPersistenceService; private readonly IItemFilterPersistenceService _itemFilterPersistenceService;
private readonly IItemFilterScriptFactory _itemFilterScriptFactory;
private readonly IItemFilterScriptViewModelFactory _itemFilterScriptViewModelFactory; private readonly IItemFilterScriptViewModelFactory _itemFilterScriptViewModelFactory;
public ItemFilterScriptRepository(IItemFilterPersistenceService itemFilterPersistenceService, public ItemFilterScriptRepository(IItemFilterPersistenceService itemFilterPersistenceService,
IItemFilterScriptFactory itemFilterScriptFactory,
IItemFilterScriptViewModelFactory itemFilterScriptViewModelFactory) IItemFilterScriptViewModelFactory itemFilterScriptViewModelFactory)
{ {
_itemFilterPersistenceService = itemFilterPersistenceService; _itemFilterPersistenceService = itemFilterPersistenceService;
_itemFilterScriptFactory = itemFilterScriptFactory;
_itemFilterScriptViewModelFactory = itemFilterScriptViewModelFactory; _itemFilterScriptViewModelFactory = itemFilterScriptViewModelFactory;
} }
@ -37,7 +41,7 @@ namespace Filtration.Repositories
public IItemFilterScriptViewModel NewScript() public IItemFilterScriptViewModel NewScript()
{ {
var newScript = new ItemFilterScript(); var newScript = _itemFilterScriptFactory.Create();
var newViewModel = _itemFilterScriptViewModelFactory.Create(); var newViewModel = _itemFilterScriptViewModelFactory.Create();
newViewModel.Initialise(newScript, true); newViewModel.Initialise(newScript, true);

View File

@ -11,8 +11,8 @@ namespace Filtration.Services
{ {
void SetItemFilterScriptDirectory(string path); void SetItemFilterScriptDirectory(string path);
string ItemFilterScriptDirectory { get; } string ItemFilterScriptDirectory { get; }
Task<ItemFilterScript> LoadItemFilterScriptAsync(string filePath); Task<IItemFilterScript> LoadItemFilterScriptAsync(string filePath);
Task SaveItemFilterScriptAsync(ItemFilterScript script); Task SaveItemFilterScriptAsync(IItemFilterScript script);
string DefaultPathOfExileDirectory(); string DefaultPathOfExileDirectory();
} }
@ -59,9 +59,9 @@ namespace Filtration.Services
Settings.Default.DefaultFilterDirectory = path; Settings.Default.DefaultFilterDirectory = path;
} }
public async Task<ItemFilterScript> LoadItemFilterScriptAsync(string filePath) public async Task<IItemFilterScript> LoadItemFilterScriptAsync(string filePath)
{ {
ItemFilterScript loadedScript = null; IItemFilterScript loadedScript = null;
await Task.Run(() => await Task.Run(() =>
{ {
loadedScript = _itemFilterScriptTranslator.TranslateStringToItemFilterScript( loadedScript = _itemFilterScriptTranslator.TranslateStringToItemFilterScript(
@ -76,7 +76,7 @@ namespace Filtration.Services
return loadedScript; return loadedScript;
} }
public async Task SaveItemFilterScriptAsync(ItemFilterScript script) public async Task SaveItemFilterScriptAsync(IItemFilterScript script)
{ {
await Task.Run(() => await Task.Run(() =>
{ {

View File

@ -25,7 +25,7 @@ namespace Filtration.ViewModels
{ {
internal interface IItemFilterScriptViewModel : IEditableDocument internal interface IItemFilterScriptViewModel : IEditableDocument
{ {
ItemFilterScript Script { get; } IItemFilterScript Script { get; }
IItemFilterBlockViewModelBase SelectedBlockViewModel { get; set; } IItemFilterBlockViewModelBase SelectedBlockViewModel { get; set; }
IItemFilterCommentBlockViewModel CommentBlockBrowserBrowserSelectedBlockViewModel { get; set; } IItemFilterCommentBlockViewModel CommentBlockBrowserBrowserSelectedBlockViewModel { get; set; }
IEnumerable<IItemFilterCommentBlockViewModel> ItemFilterCommentBlockViewModels { get; } IEnumerable<IItemFilterCommentBlockViewModel> ItemFilterCommentBlockViewModels { get; }
@ -35,7 +35,7 @@ namespace Filtration.ViewModels
string Description { get; set; } string Description { get; set; }
string DisplayName { get; } string DisplayName { get; }
void Initialise(ItemFilterScript itemFilterScript, bool newScript); void Initialise(IItemFilterScript itemFilterScript, bool newScript);
void RemoveDirtyFlag(); void RemoveDirtyFlag();
void SetDirtyFlag(); void SetDirtyFlag();
bool HasSelectedEnabledBlock(); bool HasSelectedEnabledBlock();
@ -294,7 +294,7 @@ namespace Filtration.ViewModels
} }
} }
public ItemFilterScript Script { get; private set; } public IItemFilterScript Script { get; private set; }
public bool IsDirty public bool IsDirty
{ {
@ -341,7 +341,7 @@ namespace Filtration.ViewModels
private bool _filenameIsFake; private bool _filenameIsFake;
private bool _showAdvanced; private bool _showAdvanced;
public void Initialise(ItemFilterScript itemFilterScript, bool newScript) public void Initialise(IItemFilterScript itemFilterScript, bool newScript)
{ {
ItemFilterBlockViewModels.Clear(); ItemFilterBlockViewModels.Clear();

View File

@ -1,7 +1,6 @@
using System.Collections.ObjectModel; using System.Collections.ObjectModel;
using System.Linq; using System.Linq;
using System.Windows.Media; using System.Windows.Media;
using Filtration.Common.ViewModels;
using Filtration.ObjectModel; using Filtration.ObjectModel;
using Filtration.ObjectModel.BlockItemTypes; using Filtration.ObjectModel.BlockItemTypes;
using Filtration.Views; using Filtration.Views;
@ -13,13 +12,13 @@ namespace Filtration.ViewModels
{ {
internal interface IReplaceColorsViewModel internal interface IReplaceColorsViewModel
{ {
void Initialise(ItemFilterScript itemFilterScript, IItemFilterBlock initialiseFromBlock); void Initialise(IItemFilterScript itemFilterScript, IItemFilterBlock initialiseFromBlock);
void Initialise(ItemFilterScript itemFilterScript); void Initialise(IItemFilterScript itemFilterScript);
} }
internal class ReplaceColorsViewModel : ViewModelBase, IReplaceColorsViewModel internal class ReplaceColorsViewModel : ViewModelBase, IReplaceColorsViewModel
{ {
private ItemFilterScript _itemFilterScript; private IItemFilterScript _itemFilterScript;
private ReplaceColorsParameterSet _replaceColorsParameterSet; private ReplaceColorsParameterSet _replaceColorsParameterSet;
public ReplaceColorsViewModel() public ReplaceColorsViewModel()
@ -29,7 +28,7 @@ namespace Filtration.ViewModels
public RelayCommand ReplaceColorsCommand { get; private set; } public RelayCommand ReplaceColorsCommand { get; private set; }
public void Initialise(ItemFilterScript itemFilterScript, IItemFilterBlock initialiseFromBlock) public void Initialise(IItemFilterScript itemFilterScript, IItemFilterBlock initialiseFromBlock)
{ {
_replaceColorsParameterSet = new ReplaceColorsParameterSet(); _replaceColorsParameterSet = new ReplaceColorsParameterSet();
@ -67,7 +66,7 @@ namespace Filtration.ViewModels
public Color NewTextColor public Color NewTextColor
{ {
get { return _replaceColorsParameterSet.NewTextColor; } get => _replaceColorsParameterSet.NewTextColor;
set set
{ {
_replaceColorsParameterSet.NewTextColor = value; _replaceColorsParameterSet.NewTextColor = value;
@ -82,7 +81,7 @@ namespace Filtration.ViewModels
public bool ReplaceTextColor public bool ReplaceTextColor
{ {
get { return _replaceColorsParameterSet.ReplaceTextColor; } get => _replaceColorsParameterSet.ReplaceTextColor;
set set
{ {
_replaceColorsParameterSet.ReplaceTextColor = value; _replaceColorsParameterSet.ReplaceTextColor = value;
@ -92,7 +91,7 @@ namespace Filtration.ViewModels
public Color NewBackgroundColor public Color NewBackgroundColor
{ {
get { return _replaceColorsParameterSet.NewBackgroundColor; } get => _replaceColorsParameterSet.NewBackgroundColor;
set set
{ {
_replaceColorsParameterSet.NewBackgroundColor = value; _replaceColorsParameterSet.NewBackgroundColor = value;
@ -107,7 +106,7 @@ namespace Filtration.ViewModels
public bool ReplaceBackgroundColor public bool ReplaceBackgroundColor
{ {
get { return _replaceColorsParameterSet.ReplaceBackgroundColor; } get => _replaceColorsParameterSet.ReplaceBackgroundColor;
set set
{ {
_replaceColorsParameterSet.ReplaceBackgroundColor = value; _replaceColorsParameterSet.ReplaceBackgroundColor = value;
@ -117,7 +116,7 @@ namespace Filtration.ViewModels
public Color NewBorderColor public Color NewBorderColor
{ {
get { return _replaceColorsParameterSet.NewBorderColor; } get => _replaceColorsParameterSet.NewBorderColor;
set set
{ {
_replaceColorsParameterSet.NewBorderColor = value; _replaceColorsParameterSet.NewBorderColor = value;
@ -132,7 +131,7 @@ namespace Filtration.ViewModels
public bool ReplaceBorderColor public bool ReplaceBorderColor
{ {
get { return _replaceColorsParameterSet.ReplaceBorderColor; } get => _replaceColorsParameterSet.ReplaceBorderColor;
set set
{ {
_replaceColorsParameterSet.ReplaceBorderColor = value; _replaceColorsParameterSet.ReplaceBorderColor = value;
@ -142,7 +141,7 @@ namespace Filtration.ViewModels
public ReplaceColorsParameterSet ReplaceColorsParameterSet => _replaceColorsParameterSet; public ReplaceColorsParameterSet ReplaceColorsParameterSet => _replaceColorsParameterSet;
public void Initialise(ItemFilterScript itemFilterScript) public void Initialise(IItemFilterScript itemFilterScript)
{ {
_replaceColorsParameterSet = new ReplaceColorsParameterSet(); _replaceColorsParameterSet = new ReplaceColorsParameterSet();
_itemFilterScript = itemFilterScript; _itemFilterScript = itemFilterScript;

View File

@ -17,9 +17,9 @@
<KeyBinding Command="{Binding CopyBlockStyleCommand}" Modifiers="Shift+Control" Key="C" /> <KeyBinding Command="{Binding CopyBlockStyleCommand}" Modifiers="Shift+Control" Key="C" />
<KeyBinding Command="{Binding PasteBlockStyleCommand}" Modifiers="Shift+Control" Key="V" /> <KeyBinding Command="{Binding PasteBlockStyleCommand}" Modifiers="Shift+Control" Key="V" />
</UserControl.InputBindings> </UserControl.InputBindings>
<utility:RoutedCommandHandlers.Commands> <!--<utility:RoutedCommandHandlers.Commands>
<utility:RoutedCommandHandler RoutedCommand="{StaticResource MoveBlockUpRoutedCommand}" Command="{Binding MoveBlockUpCommand}" IsActive="{Binding IsActiveDocument}" /> <utility:RoutedCommandHandler RoutedCommand="{StaticResource MoveBlockUpRoutedCommand}" Command="{Binding MoveBlockUpCommand}" IsActive="{Binding IsActiveDocument}" />
</utility:RoutedCommandHandlers.Commands> </utility:RoutedCommandHandlers.Commands>-->
<UserControl.Resources> <UserControl.Resources>
<ResourceDictionary> <ResourceDictionary>
<ResourceDictionary.MergedDictionaries> <ResourceDictionary.MergedDictionaries>
@ -42,7 +42,6 @@
</Grid.RowDefinitions> </Grid.RowDefinitions>
<Border Grid.Row="0" BorderThickness="1" BorderBrush="DarkGray" Margin="5,5,5,0"> <Border Grid.Row="0" BorderThickness="1" BorderBrush="DarkGray" Margin="5,5,5,0">
<StackPanel Margin="2,2,2,2"> <StackPanel Margin="2,2,2,2">
<Button Command="{StaticResource MoveBlockUpRoutedCommand}">MOVE BLOCK UP TEST BUTTON</Button>
<Expander Style="{StaticResource ExpanderRightAlignStyle}"> <Expander Style="{StaticResource ExpanderRightAlignStyle}">
<Expander.Header> <Expander.Header>
<TextBlock Text="Script Description" VerticalAlignment="Center" /> <TextBlock Text="Script Description" VerticalAlignment="Center" />

View File

@ -8,7 +8,7 @@
<Grid> <Grid>
<TextBlock FontStyle="Italic" Margin="5" FontSize="13"> <TextBlock FontStyle="Italic" Margin="5" FontSize="13">
Welcome to Filtration, to get started either Welcome to Filtration, to get started either
<Hyperlink Command="{Binding NewScriptCommand}">create a new script</Hyperlink> or <Hyperlink Command="{StaticResource OpenScriptRoutedCommand}">open an existing script</Hyperlink> <Hyperlink Command="{Binding NewScriptCommand}">create a new script</Hyperlink> or <Hyperlink Command="{Binding OpenScriptCommand}">open an existing script</Hyperlink>
</TextBlock> </TextBlock>
</Grid> </Grid>
</UserControl> </UserControl>