diff --git a/Filtration.ObjectModel/ItemFilterBlock.cs b/Filtration.ObjectModel/ItemFilterBlock.cs index 58e2445..5b7e4c6 100644 --- a/Filtration.ObjectModel/ItemFilterBlock.cs +++ b/Filtration.ObjectModel/ItemFilterBlock.cs @@ -13,8 +13,10 @@ namespace Filtration.ObjectModel public ItemFilterBlock() { BlockItems = new ObservableCollection {new ActionBlockItem(BlockAction.Show)}; + Enabled = true; } - + + public bool Enabled { get; set; } public string Description { get; set; } public ItemFilterBlockGroup BlockGroup diff --git a/Filtration.Tests/Translators/TestItemFilterBlockTranslator.cs b/Filtration.Tests/Translators/TestItemFilterBlockTranslator.cs index d37f5de..91e6573 100644 --- a/Filtration.Tests/Translators/TestItemFilterBlockTranslator.cs +++ b/Filtration.Tests/Translators/TestItemFilterBlockTranslator.cs @@ -25,6 +25,36 @@ namespace Filtration.Tests.Translators _testUtility = new ItemFilterBlockTranslatorTestUtility(); } + [Test] + public void TranslateStringToItemFilterBlock_NotDisabled_SetsBlockEnabledTrue() + { + // Arrange + var inputString = "Show" + Environment.NewLine + + " ItemLevel >= 55"; + + // Act + var result = _testUtility.Translator.TranslateStringToItemFilterBlock(inputString, null); + + // Assert + Assert.AreEqual(true, result.Enabled); + } + + [Test] + public void TranslateStringToItemFilterBlock_DisabledBlock_SetsBlockEnabledFalse() + { + // Arrange + var inputString = "HideDisabled" + Environment.NewLine + + " ItemLevel >= 55"; + + // Act + var result = _testUtility.Translator.TranslateStringToItemFilterBlock(inputString, null); + + // Assert + Assert.AreEqual(2, result.BlockItems.Count); + Assert.AreEqual(BlockAction.Hide, result.Action); + Assert.AreEqual(false, result.Enabled); + } + [Test] public void TranslateStringToItemFilterBlock_NoDescriptionComment_ReturnsCorrectObject() { @@ -1264,6 +1294,26 @@ namespace Filtration.Tests.Translators Assert.AreEqual(expectedResult, result); } + [Test] + public void TranslateItemFilterBlockToString_DisabledBlock_ReturnsCorrectString() + { + // Arrange + var expectedResult = "#Disabled Block Start" + Environment.NewLine + + "#Show" + Environment.NewLine + + "# Width = 4" + Environment.NewLine + + "#Disabled Block End"; + + + _testUtility.TestBlock.Enabled = false; + _testUtility.TestBlock.BlockItems.Add(new WidthBlockItem(FilterPredicateOperator.Equal, 4)); + + // Act + var result = _testUtility.Translator.TranslateItemFilterBlockToString(_testUtility.TestBlock); + + // Assert + Assert.AreEqual(expectedResult, result); + } + [Test] public void TranslateItemFilterBlockToString_Everything_ReturnsCorrectString() { diff --git a/Filtration.Tests/Translators/TestItemFilterScriptTranslator.cs b/Filtration.Tests/Translators/TestItemFilterScriptTranslator.cs index 056b58a..766dd19 100644 --- a/Filtration.Tests/Translators/TestItemFilterScriptTranslator.cs +++ b/Filtration.Tests/Translators/TestItemFilterScriptTranslator.cs @@ -253,6 +253,79 @@ namespace Filtration.Tests.Translators Assert.IsNullOrEmpty(firstBlock.Description); } + [Test] + public void TranslateStringToItemFilterScript_DisabledBlock_ReturnsCorrectBlockCount() + { + // Arrange + var testInputScript = "Show" + Environment.NewLine + + " ItemLevel > 2" + Environment.NewLine + + " SetTextColor 255 40 0" + Environment.NewLine + + Environment.NewLine + + "#Disabled Block Start" + Environment.NewLine + + "#Show" + Environment.NewLine + + "# ItemLevel > 2" + Environment.NewLine + + "# SetTextColor 255 215 0" + Environment.NewLine + + "# SetBorderColor 255 105 180" + Environment.NewLine + + "# SetFontSize 32" + Environment.NewLine + + "#Disabled Block End" + Environment.NewLine + + Environment.NewLine + + "Show" + Environment.NewLine + + " ItemLevel > 20" + Environment.NewLine + + " SetTextColor 255 255 0"; + + + var blockTranslator = new ItemFilterBlockTranslator(_testUtility.MockBlockGroupHierarchyBuilder.Object); + var translator = new ItemFilterScriptTranslator(blockTranslator, + _testUtility.MockBlockGroupHierarchyBuilder.Object); + + // Act + var result = translator.TranslateStringToItemFilterScript(testInputScript); + + // Assert + Assert.AreEqual(3, result.ItemFilterBlocks.Count); + } + + [Test] + public void TranslateStringToItemFilterScript_DisabledBlock_ReturnsCorrectBlocks() + { + // Arrange + var testInputScript = "Show" + Environment.NewLine + + " ItemLevel > 2" + Environment.NewLine + + " SetTextColor 255 40 0" + Environment.NewLine + + Environment.NewLine + + "#Disabled Block Start" + Environment.NewLine + + "#Show" + Environment.NewLine + + "# ItemLevel > 2" + Environment.NewLine + + "# SetTextColor 255 215 0" + Environment.NewLine + + "# SetBorderColor 255 105 180" + Environment.NewLine + + "# SetFontSize 32" + Environment.NewLine + + "#Disabled Block End" + Environment.NewLine + + Environment.NewLine + + "Show" + Environment.NewLine + + " ItemLevel > 20" + Environment.NewLine + + " SetTextColor 255 255 0"; + + + var blockTranslator = new ItemFilterBlockTranslator(_testUtility.MockBlockGroupHierarchyBuilder.Object); + var translator = new ItemFilterScriptTranslator(blockTranslator, + _testUtility.MockBlockGroupHierarchyBuilder.Object); + + // Act + var result = translator.TranslateStringToItemFilterScript(testInputScript); + + // Assert + Assert.AreEqual(3, result.ItemFilterBlocks.Count); + + var firstBlock = result.ItemFilterBlocks.First(); + var secondBlock = result.ItemFilterBlocks.Skip(1).First(); + var thirdBlock = result.ItemFilterBlocks.Skip(2).First(); + + Assert.AreEqual(3, firstBlock.BlockItems.Count); + Assert.AreEqual(5, secondBlock.BlockItems.Count); + Assert.AreEqual(3, thirdBlock.BlockItems.Count); + + } + private class ItemFilterScriptTranslatorTestUtility { public ItemFilterScriptTranslatorTestUtility() diff --git a/Filtration/Filtration.csproj b/Filtration/Filtration.csproj index 8d1aff4..6383915 100644 --- a/Filtration/Filtration.csproj +++ b/Filtration/Filtration.csproj @@ -429,6 +429,8 @@ + + Always diff --git a/Filtration/Properties/AssemblyInfo.cs b/Filtration/Properties/AssemblyInfo.cs index e28c716..5931e5e 100644 --- a/Filtration/Properties/AssemblyInfo.cs +++ b/Filtration/Properties/AssemblyInfo.cs @@ -50,7 +50,7 @@ using System.Windows; // You can specify all the values or you can default the Build and Revision Numbers // by using the '*' as shown below: // [assembly: AssemblyVersion("1.0.*")] -[assembly: AssemblyVersion("0.6.*")] +[assembly: AssemblyVersion("0.7.*")] [assembly: InternalsVisibleTo("Filtration.Tests")] [assembly: InternalsVisibleTo("DynamicProxyGenAssembly2")] \ No newline at end of file diff --git a/Filtration/Resources/Icons/standby_disabled_icon.png b/Filtration/Resources/Icons/standby_disabled_icon.png new file mode 100644 index 0000000..2d2208d Binary files /dev/null and b/Filtration/Resources/Icons/standby_disabled_icon.png differ diff --git a/Filtration/Resources/Icons/standby_enabled_icon.png b/Filtration/Resources/Icons/standby_enabled_icon.png new file mode 100644 index 0000000..dcdd2b7 Binary files /dev/null and b/Filtration/Resources/Icons/standby_enabled_icon.png differ diff --git a/Filtration/Translators/ItemFilterBlockTranslator.cs b/Filtration/Translators/ItemFilterBlockTranslator.cs index 7522673..78b8937 100644 --- a/Filtration/Translators/ItemFilterBlockTranslator.cs +++ b/Filtration/Translators/ItemFilterBlockTranslator.cs @@ -28,6 +28,7 @@ namespace Filtration.Translators private readonly IBlockGroupHierarchyBuilder _blockGroupHierarchyBuilder; private const string Indent = " "; private readonly string _newLine = Environment.NewLine + Indent; + private readonly string _disabledNewLine = Environment.NewLine + "#" + Indent; private ThemeComponentCollection _masterComponentCollection; public ItemFilterBlockTranslator(IBlockGroupHierarchyBuilder blockGroupHierarchyBuilder) @@ -42,6 +43,7 @@ namespace Filtration.Translators _masterComponentCollection = masterComponentCollection; var block = new ItemFilterBlock(); var showHideFound = false; + foreach (var line in new LineReader(() => new StringReader(inputString))) { @@ -62,6 +64,7 @@ namespace Filtration.Translators var adjustedLine = line.Replace("#", " # "); var trimmedLine = adjustedLine.TrimStart(' '); + var spaceOrEndOfLinePos = trimmedLine.IndexOf(" ", StringComparison.Ordinal) > 0 ? trimmedLine.IndexOf(" ", StringComparison.Ordinal) : trimmedLine.Length; var lineOption = trimmedLine.Substring(0, spaceOrEndOfLinePos); @@ -70,11 +73,25 @@ namespace Filtration.Translators case "Show": showHideFound = true; block.Action = BlockAction.Show; + block.Enabled = true; AddBlockGroupToBlock(block, trimmedLine); break; case "Hide": showHideFound = true; block.Action = BlockAction.Hide; + block.Enabled = true; + AddBlockGroupToBlock(block, trimmedLine); + break; + case "ShowDisabled": + showHideFound = true; + block.Action = BlockAction.Show; + block.Enabled = false; + AddBlockGroupToBlock(block, trimmedLine); + break; + case "HideDisabled": + showHideFound = true; + block.Action = BlockAction.Hide; + block.Enabled = false; AddBlockGroupToBlock(block, trimmedLine); break; case "ItemLevel": @@ -399,12 +416,17 @@ namespace Filtration.Translators var outputString = string.Empty; + if (!block.Enabled) + { + outputString += "#Disabled Block Start" + Environment.NewLine; + } + if (!string.IsNullOrEmpty(block.Description)) { outputString += "# " + block.Description + Environment.NewLine; } - outputString += block.Action.GetAttributeDescription(); + outputString += (!block.Enabled ? "#" : string.Empty) + block.Action.GetAttributeDescription(); if (block.BlockGroup != null) { @@ -416,9 +438,14 @@ namespace Filtration.Translators { if (blockItem.OutputText != string.Empty) { - outputString += _newLine + blockItem.OutputText; + outputString += (!block.Enabled ? _disabledNewLine : _newLine) + blockItem.OutputText; } } + + if (!block.Enabled) + { + outputString += Environment.NewLine + "#Disabled Block End"; + } return outputString; } diff --git a/Filtration/Translators/ItemFilterScriptTranslator.cs b/Filtration/Translators/ItemFilterScriptTranslator.cs index c5b53d0..0036261 100644 --- a/Filtration/Translators/ItemFilterScriptTranslator.cs +++ b/Filtration/Translators/ItemFilterScriptTranslator.cs @@ -3,6 +3,7 @@ using System.Collections.Generic; using System.IO; using System.Linq; using System.Text.RegularExpressions; +using System.Windows.Documents; using Castle.Core.Internal; using Filtration.ObjectModel; using Filtration.Properties; @@ -28,12 +29,63 @@ namespace Filtration.Translators _blockGroupHierarchyBuilder = blockGroupHierarchyBuilder; } + public string PreprocessDisabledBlocks(string inputString) + { + bool inDisabledBlock = false; + + var lines = Regex.Split(inputString, "\r\n|\r|\n").ToList(); + var linesToRemove = new List(); + + for (var i = 0; i < lines.Count; i++) + { + if (lines[i].StartsWith("#Disabled Block Start")) + { + inDisabledBlock = true; + linesToRemove.Add(i); + continue; + } + if (inDisabledBlock) + { + if (lines[i].StartsWith("#Disabled Block End")) + { + inDisabledBlock = false; + linesToRemove.Add(i); + continue; + } + + lines[i] = lines[i].TrimStart('#'); + var spaceOrEndOfLinePos = lines[i].IndexOf(" ", StringComparison.Ordinal) > 0 ? lines[i].IndexOf(" ", StringComparison.Ordinal) : lines[i].Length; + var lineOption = lines[i].Substring(0, spaceOrEndOfLinePos); + if (lineOption == "Show") + { + lines[i] = lines[i].Replace("Show", "ShowDisabled"); + } + else if (lineOption == "Hide") + { + lines[i] = lines[i].Replace("Hide", "HideDisabled"); + } + } + } + + for (var i = linesToRemove.Count - 1; i >= 0; i--) + { + lines.RemoveAt(linesToRemove[i]); + } + + return lines.Aggregate((c, n) => c + Environment.NewLine + n); + } + public ItemFilterScript TranslateStringToItemFilterScript(string inputString) { var script = new ItemFilterScript(); _blockGroupHierarchyBuilder.Initialise(script.ItemFilterBlockGroups.First()); inputString = inputString.Replace("\t", ""); + if (inputString.Contains("#Disabled Block Start")) + { + inputString = PreprocessDisabledBlocks(inputString); + } + var conditionBoundaries = IdentifyBlockBoundaries(inputString); var lines = Regex.Split(inputString, "\r\n|\r|\n"); @@ -85,7 +137,10 @@ namespace Filtration.Translators // as it represents the block description. // currentLine > 2 caters for an edge case where the script description is a single line and the first // block has no description. This prevents the script description from being assigned to the first block's description. - blockBoundaries.AddLast(previousLine.StartsWith("#") && !previousLine.StartsWith("# Section:") && currentLine > 2 ? currentLine - 2 : currentLine - 1); + blockBoundaries.AddLast(previousLine.StartsWith("#") && !previousLine.StartsWith("# Section:") && + currentLine > 2 + ? currentLine - 2 + : currentLine - 1); } previousLine = line; } diff --git a/Filtration/ViewModels/ItemFilterBlockViewModel.cs b/Filtration/ViewModels/ItemFilterBlockViewModel.cs index 51a3ddc..03c0428 100644 --- a/Filtration/ViewModels/ItemFilterBlockViewModel.cs +++ b/Filtration/ViewModels/ItemFilterBlockViewModel.cs @@ -21,6 +21,7 @@ namespace Filtration.ViewModels bool IsDirty { get; set; } bool IsExpanded { get; set; } ItemFilterBlock Block { get; } + bool BlockEnabled { get; set; } void RefreshBlockPreview(); } @@ -209,6 +210,20 @@ namespace Filtration.ViewModels } } + public bool BlockEnabled + { + get { return Block.Enabled; } + set + { + if (Block.Enabled != value) + { + Block.Enabled = value; + IsDirty = true; + RaisePropertyChanged(); + } + } + } + public string BlockDescription { get diff --git a/Filtration/ViewModels/ItemFilterScriptViewModel.cs b/Filtration/ViewModels/ItemFilterScriptViewModel.cs index e1a894d..4990bb4 100644 --- a/Filtration/ViewModels/ItemFilterScriptViewModel.cs +++ b/Filtration/ViewModels/ItemFilterScriptViewModel.cs @@ -38,9 +38,13 @@ namespace Filtration.ViewModels void Initialise(ItemFilterScript itemFilterScript, bool newScript); void RemoveDirtyFlag(); void SetDirtyFlag(); + bool HasSelectedEnabledBlock(); + bool HasSelectedDisabledBlock(); RelayCommand AddBlockCommand { get; } RelayCommand AddSectionCommand { get; } + RelayCommand DisableBlockCommand { get; } + RelayCommand EnableBlockCommand { get; } RelayCommand DeleteBlockCommand { get; } RelayCommand MoveBlockUpCommand { get; } RelayCommand MoveBlockDownCommand { get; } @@ -104,6 +108,8 @@ namespace Filtration.ViewModels MoveBlockToBottomCommand = new RelayCommand(OnMoveBlockToBottomCommand, () => SelectedBlockViewModel != null); AddBlockCommand = new RelayCommand(OnAddBlockCommand); AddSectionCommand = new RelayCommand(OnAddSectionCommand, () => SelectedBlockViewModel != null); + DisableBlockCommand = new RelayCommand(OnDisableBlockCommand, HasSelectedEnabledBlock); + EnableBlockCommand = new RelayCommand(OnEnableBlockCommand, HasSelectedDisabledBlock); CopyBlockCommand = new RelayCommand(OnCopyBlockCommand, () => SelectedBlockViewModel != null); CopyBlockStyleCommand = new RelayCommand(OnCopyBlockStyleCommand, () => SelectedBlockViewModel != null); PasteBlockCommand = new RelayCommand(OnPasteBlockCommand, () => SelectedBlockViewModel != null); @@ -128,6 +134,8 @@ namespace Filtration.ViewModels public RelayCommand MoveBlockToBottomCommand { get; private set; } public RelayCommand AddBlockCommand { get; private set; } public RelayCommand AddSectionCommand { get; private set; } + public RelayCommand EnableBlockCommand { get; private set; } + public RelayCommand DisableBlockCommand { get; private set; } public RelayCommand CopyBlockCommand { get; private set; } public RelayCommand CopyBlockStyleCommand { get; private set; } public RelayCommand PasteBlockCommand { get; private set; } @@ -215,6 +223,21 @@ namespace Filtration.ViewModels } } + public bool HasSelectedBlock() + { + return SelectedBlockViewModel != null; + } + + public bool HasSelectedEnabledBlock() + { + return HasSelectedBlock() && !(SelectedBlockViewModel.Block is ItemFilterSection) && SelectedBlockViewModel.BlockEnabled; + } + + public bool HasSelectedDisabledBlock() + { + return HasSelectedBlock() && !(SelectedBlockViewModel.Block is ItemFilterSection) && !SelectedBlockViewModel.BlockEnabled; + } + public IItemFilterBlockViewModel SelectedBlockViewModel { get { return _selectedBlockViewModel; } @@ -767,5 +790,25 @@ namespace Filtration.ViewModels } SelectedBlockViewModel = null; } + + private void OnDisableBlockCommand() + { + DisableBlock(SelectedBlockViewModel); + } + + private void DisableBlock(IItemFilterBlockViewModel targetBlockViewModel) + { + targetBlockViewModel.BlockEnabled = false; + } + + private void OnEnableBlockCommand() + { + EnableBlock(SelectedBlockViewModel); + } + + private void EnableBlock(IItemFilterBlockViewModel targetBlockViewModel) + { + targetBlockViewModel.BlockEnabled = true; + } } } diff --git a/Filtration/ViewModels/MainWindowViewModel.cs b/Filtration/ViewModels/MainWindowViewModel.cs index aaa4413..53efb04 100644 --- a/Filtration/ViewModels/MainWindowViewModel.cs +++ b/Filtration/ViewModels/MainWindowViewModel.cs @@ -96,7 +96,10 @@ namespace Filtration.ViewModels AddBlockCommand = new RelayCommand(OnAddBlockCommand, () => _activeDocumentIsScript); AddSectionCommand = new RelayCommand(OnAddSectionCommand, () => _activeDocumentIsScript); DeleteBlockCommand = new RelayCommand(OnDeleteBlockCommand, () => _activeDocumentIsScript && ActiveScriptHasSelectedBlock); - + DisableBlockCommand = new RelayCommand(OnDisableBlockCommand, + () => _activeDocumentIsScript && ActiveScriptHasSelectedEnabledBlock); + EnableBlockCommand = new RelayCommand(OnEnableBlockCommand, + () => _activeDocumentIsScript && ActiveScriptHasSelectedDisabledBlock); OpenAboutWindowCommand = new RelayCommand(OnOpenAboutWindowCommand); ReplaceColorsCommand = new RelayCommand(OnReplaceColorsCommand, () => _activeDocumentIsScript); @@ -198,6 +201,8 @@ namespace Filtration.ViewModels public RelayCommand AddBlockCommand { get; private set; } public RelayCommand AddSectionCommand { get; private set; } public RelayCommand DeleteBlockCommand { get; private set; } + public RelayCommand DisableBlockCommand { get; private set; } + public RelayCommand EnableBlockCommand { get; private set; } public RelayCommand MoveBlockUpCommand { get; private set; } public RelayCommand MoveBlockDownCommand { get; private set; } @@ -305,6 +310,16 @@ namespace Filtration.ViewModels { get { return AvalonDockWorkspaceViewModel.ActiveScriptViewModel.SelectedBlockViewModel != null; } } + + public bool ActiveScriptHasSelectedEnabledBlock + { + get { return AvalonDockWorkspaceViewModel.ActiveScriptViewModel.HasSelectedEnabledBlock(); } + } + + public bool ActiveScriptHasSelectedDisabledBlock + { + get { return AvalonDockWorkspaceViewModel.ActiveScriptViewModel.HasSelectedDisabledBlock(); } + } public bool ActiveThemeIsEditable { @@ -580,6 +595,16 @@ namespace Filtration.ViewModels _avalonDockWorkspaceViewModel.ActiveScriptViewModel.DeleteBlockCommand.Execute(null); } + private void OnDisableBlockCommand() + { + _avalonDockWorkspaceViewModel.ActiveScriptViewModel.DisableBlockCommand.Execute(null); + } + + private void OnEnableBlockCommand() + { + _avalonDockWorkspaceViewModel.ActiveScriptViewModel.EnableBlockCommand.Execute(null); + } + private void OnExpandAllBlocksCommand() { _avalonDockWorkspaceViewModel.ActiveScriptViewModel.ExpandAllBlocksCommand.Execute(null); diff --git a/Filtration/Views/IconsDictionary.xaml b/Filtration/Views/IconsDictionary.xaml index f4fea97..281fa83 100644 --- a/Filtration/Views/IconsDictionary.xaml +++ b/Filtration/Views/IconsDictionary.xaml @@ -31,4 +31,6 @@ + + \ No newline at end of file diff --git a/Filtration/Views/ItemFilterBlockView.xaml b/Filtration/Views/ItemFilterBlockView.xaml index f40dc24..04c2101 100644 --- a/Filtration/Views/ItemFilterBlockView.xaml +++ b/Filtration/Views/ItemFilterBlockView.xaml @@ -41,6 +41,11 @@ + + + + + @@ -62,8 +67,8 @@ - - + + @@ -89,6 +94,7 @@ + @@ -121,9 +127,9 @@ - + - +