Implemented script-level undo/redo (currently hidden in UI)

This commit is contained in:
Ben Wallis
2017-12-07 18:14:47 +00:00
parent fee2a4dd99
commit d84b17ced3
36 changed files with 888 additions and 384 deletions

View File

@@ -184,11 +184,14 @@
<Compile Include="Utility\RoutedCommandHandler.cs" />
<Compile Include="Utility\RoutedCommandHandlers.cs" />
<Compile Include="ViewModels\AvalonDockWorkspaceViewModel.cs" />
<Compile Include="ViewModels\IItemFilterCommentBlockViewModelFactory.cs" />
<Compile Include="ViewModels\Factories\IItemFilterCommentBlockViewModelFactory.cs" />
<Compile Include="ViewModels\Factories\ItemFilterBlockBaseViewModelFactory.cs" />
<Compile Include="ViewModels\ItemFilterBlockViewModelBase.cs" />
<Compile Include="ViewModels\ItemFilterCommentBlockViewModel.cs" />
<Compile Include="ViewModels\SettingsPageViewModel.cs" />
<Compile Include="ViewModels\ToolPanes\BlockGroupBrowserViewModel.cs" />
<Compile Include="ViewModels\IItemFilterScriptViewModelFactory.cs" />
<Compile Include="ViewModels\IItemFilterBlockViewModelFactory.cs" />
<Compile Include="ViewModels\Factories\IItemFilterScriptViewModelFactory.cs" />
<Compile Include="ViewModels\Factories\IItemFilterBlockViewModelFactory.cs" />
<Compile Include="ViewModels\ItemFilterBlockGroupViewModel.cs" />
<Compile Include="ViewModels\ItemFilterBlockViewModel.cs" />
<Compile Include="ViewModels\ItemFilterScriptViewModel.cs" />
@@ -443,6 +446,8 @@
<Resource Include="Resources\Icons\ThemeComponentDelete.ico" />
<Resource Include="Resources\Icons\standby_disabled_icon.png" />
<Resource Include="Resources\Icons\standby_enabled_icon.png" />
<Resource Include="Resources\Icons\redo_icon.png" />
<Resource Include="Resources\Icons\undo_icon.png" />
<Content Include="Resources\ItemBaseTypes.txt" />
<Content Include="Resources\ItemClasses.txt" />
</ItemGroup>

View File

@@ -3,6 +3,7 @@ using Filtration.ObjectModel;
using Filtration.ObjectModel.Factories;
using Filtration.Services;
using Filtration.ViewModels;
using Filtration.ViewModels.Factories;
namespace Filtration.Repositories
{

Binary file not shown.

After

Width:  |  Height:  |  Size: 579 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 339 B

View File

@@ -1,4 +1,4 @@
namespace Filtration.ViewModels
namespace Filtration.ViewModels.Factories
{
internal interface IItemFilterBlockViewModelFactory
{

View File

@@ -1,4 +1,4 @@
namespace Filtration.ViewModels
namespace Filtration.ViewModels.Factories
{
internal interface IItemFilterCommentBlockViewModelFactory
{

View File

@@ -1,4 +1,4 @@
namespace Filtration.ViewModels
namespace Filtration.ViewModels.Factories
{
internal interface IItemFilterScriptViewModelFactory
{

View File

@@ -0,0 +1,37 @@
using System;
using Filtration.ObjectModel;
namespace Filtration.ViewModels.Factories
{
internal interface IItemFilterBlockBaseViewModelFactory
{
IItemFilterBlockViewModelBase Create(IItemFilterBlockBase itemFilterBlockBase);
}
internal class ItemFilterBlockBaseViewModelFactory : IItemFilterBlockBaseViewModelFactory
{
private readonly IItemFilterBlockViewModelFactory _itemFilterBlockViewModelFactory;
private readonly IItemFilterCommentBlockViewModelFactory _itemFilterCommentBlockViewModelFactory;
public ItemFilterBlockBaseViewModelFactory(IItemFilterBlockViewModelFactory itemFilterBlockViewModelFactory,
IItemFilterCommentBlockViewModelFactory itemFilterCommentBlockViewModelFactory)
{
_itemFilterBlockViewModelFactory = itemFilterBlockViewModelFactory;
_itemFilterCommentBlockViewModelFactory = itemFilterCommentBlockViewModelFactory;
}
public IItemFilterBlockViewModelBase Create(IItemFilterBlockBase itemFilterBlockBase)
{
if (itemFilterBlockBase is IItemFilterBlock)
{
return _itemFilterBlockViewModelFactory.Create();
}
if (itemFilterBlockBase is IItemFilterCommentBlock)
{
return _itemFilterCommentBlockViewModelFactory.Create();
}
throw new InvalidOperationException("Unknown IItemFilterBlockBase type");
}
}
}

View File

@@ -9,7 +9,6 @@ using Filtration.ObjectModel.BlockItemBaseTypes;
using Filtration.ObjectModel.BlockItemTypes;
using Filtration.Services;
using Filtration.Views;
using GalaSoft.MvvmLight;
using GalaSoft.MvvmLight.CommandWpf;
using Xceed.Wpf.Toolkit;
@@ -17,7 +16,6 @@ namespace Filtration.ViewModels
{
internal interface IItemFilterBlockViewModel : IItemFilterBlockViewModelBase
{
void Initialise(IItemFilterBlock itemFilterBlock, ItemFilterScriptViewModel parentScriptViewModel);
bool IsExpanded { get; set; }
IItemFilterBlock Block { get; }
bool BlockEnabled { get; set; }
@@ -25,72 +23,12 @@ namespace Filtration.ViewModels
void RefreshBlockPreview();
}
internal interface IItemFilterBlockViewModelBase
{
IItemFilterBlockBase BaseBlock { get; }
bool IsDirty { get; set; }
event EventHandler BlockBecameDirty;
}
internal abstract class ItemFilterBlockViewModelBase : ViewModelBase, IItemFilterBlockViewModelBase
{
private bool _isDirty;
protected void Initialise(IItemFilterBlockBase itemfilterBlock)
{
BaseBlock = itemfilterBlock;
}
public event EventHandler BlockBecameDirty;
public IItemFilterBlockBase BaseBlock { get; protected set; }
public bool IsDirty
{
get => _isDirty;
set
{
if (value != _isDirty)
{
_isDirty = value;
RaisePropertyChanged();
BlockBecameDirty?.Invoke(this, EventArgs.Empty);
}
}
}
}
internal interface IItemFilterCommentBlockViewModel : IItemFilterBlockViewModelBase
{
void Initialise(IItemFilterCommentBlock itemFilterCommentBlock);
IItemFilterCommentBlock ItemFilterCommentBlock { get; }
string Comment { get; }
}
internal class ItemFilterCommentBlockViewModel : ItemFilterBlockViewModelBase, IItemFilterCommentBlockViewModel
{
public ItemFilterCommentBlockViewModel()
{
}
public void Initialise(IItemFilterCommentBlock itemFilterCommentBlock)
{
ItemFilterCommentBlock = itemFilterCommentBlock;
BaseBlock = itemFilterCommentBlock;
}
public IItemFilterCommentBlock ItemFilterCommentBlock { get; private set; }
public string Comment => ItemFilterCommentBlock.Comment;
}
internal class ItemFilterBlockViewModel : ItemFilterBlockViewModelBase, IItemFilterBlockViewModel
{
private readonly IStaticDataService _staticDataService;
private readonly IReplaceColorsViewModel _replaceColorsViewModel;
private readonly MediaPlayer _mediaPlayer = new MediaPlayer();
private ItemFilterScriptViewModel _parentScriptViewModel;
private IItemFilterScriptViewModel _parentScriptViewModel;
private bool _displaySettingsPopupOpen;
private bool _isExpanded;
@@ -120,8 +58,9 @@ namespace Filtration.ViewModels
PlaySoundCommand = new RelayCommand(OnPlaySoundCommand, () => HasSound);
}
public void Initialise(IItemFilterBlock itemFilterBlock, ItemFilterScriptViewModel parentScriptViewModel)
public override void Initialise(IItemFilterBlockBase itemFilterBlockBase, IItemFilterScriptViewModel parentScriptViewModel)
{
var itemFilterBlock = itemFilterBlockBase as IItemFilterBlock;
if (itemFilterBlock == null || parentScriptViewModel == null)
{
throw new ArgumentNullException(nameof(itemFilterBlock));
@@ -139,7 +78,7 @@ namespace Filtration.ViewModels
}
base.Initialise(itemFilterBlock);
base.Initialise(itemFilterBlock, parentScriptViewModel);
}
public RelayCommand CopyBlockCommand { get; }
@@ -350,7 +289,7 @@ namespace Filtration.ViewModels
private void OnAddSectionCommand()
{
_parentScriptViewModel.AddSection(this);
_parentScriptViewModel.AddCommentBlock(this);
}
private void OnDeleteBlockCommand()

View File

@@ -0,0 +1,42 @@
using System;
using Filtration.ObjectModel;
using GalaSoft.MvvmLight;
namespace Filtration.ViewModels
{
internal interface IItemFilterBlockViewModelBase
{
void Initialise(IItemFilterBlockBase itemfilterBlock, IItemFilterScriptViewModel itemFilterScriptViewModel);
IItemFilterBlockBase BaseBlock { get; }
bool IsDirty { get; set; }
event EventHandler BlockBecameDirty;
}
internal abstract class ItemFilterBlockViewModelBase : ViewModelBase, IItemFilterBlockViewModelBase
{
private bool _isDirty;
public virtual void Initialise(IItemFilterBlockBase itemfilterBlock, IItemFilterScriptViewModel itemFilterScriptViewModel)
{
BaseBlock = itemfilterBlock;
}
public event EventHandler BlockBecameDirty;
public IItemFilterBlockBase BaseBlock { get; protected set; }
public bool IsDirty
{
get => _isDirty;
set
{
if (value != _isDirty)
{
_isDirty = value;
RaisePropertyChanged();
BlockBecameDirty?.Invoke(this, EventArgs.Empty);
}
}
}
}
}

View File

@@ -0,0 +1,29 @@
using Filtration.ObjectModel;
namespace Filtration.ViewModels
{
internal interface IItemFilterCommentBlockViewModel : IItemFilterBlockViewModelBase
{
IItemFilterCommentBlock ItemFilterCommentBlock { get; }
string Comment { get; }
}
internal class ItemFilterCommentBlockViewModel : ItemFilterBlockViewModelBase, IItemFilterCommentBlockViewModel
{
public ItemFilterCommentBlockViewModel()
{
}
public override void Initialise(IItemFilterBlockBase itemfilterBlock, IItemFilterScriptViewModel itemFilterScriptViewModel)
{
ItemFilterCommentBlock = itemfilterBlock as IItemFilterCommentBlock;
BaseBlock = ItemFilterCommentBlock;
base.Initialise(itemfilterBlock, itemFilterScriptViewModel);
}
public IItemFilterCommentBlock ItemFilterCommentBlock { get; private set; }
public string Comment => ItemFilterCommentBlock.Comment;
}
}

View File

@@ -1,6 +1,7 @@
using System;
using System.Collections.Generic;
using System.Collections.ObjectModel;
using System.Collections.Specialized;
using System.ComponentModel;
using System.Diagnostics;
using System.IO;
@@ -15,8 +16,11 @@ using Filtration.Common.ViewModels;
using Filtration.Interface;
using Filtration.ObjectModel;
using Filtration.ObjectModel.BlockItemBaseTypes;
using Filtration.ObjectModel.Commands;
using Filtration.ObjectModel.Commands.ItemFilterScript;
using Filtration.Parser.Interface.Services;
using Filtration.Services;
using Filtration.ViewModels.Factories;
using GalaSoft.MvvmLight.CommandWpf;
using GalaSoft.MvvmLight.Messaging;
using NLog;
@@ -59,21 +63,25 @@ namespace Filtration.ViewModels
RelayCommand<bool> ToggleShowAdvancedCommand { get; }
RelayCommand ClearFilterCommand { get; }
void AddSection(IItemFilterBlockViewModelBase targetBlockViewModel);
void AddCommentBlock(IItemFilterBlockViewModelBase targetBlockViewModel);
void AddBlock(IItemFilterBlockViewModelBase targetBlockViewModel);
void CopyBlock(IItemFilterBlockViewModelBase targetBlockViewModel);
void CopyBlockStyle(IItemFilterBlockViewModel targetBlockViewModel);
void PasteBlock(IItemFilterBlockViewModelBase targetBlockViewModel);
void PasteBlockStyle(IItemFilterBlockViewModel targetBlockViewModel);
void DeleteBlock(IItemFilterBlockViewModelBase targetBlockViewModelBase);
void MoveBlockToTop(IItemFilterBlockViewModelBase targetBlockViewModelBase);
void MoveBlockUp(IItemFilterBlockViewModelBase targetBlockViewModelBase);
void MoveBlockDown(IItemFilterBlockViewModelBase targetBlockViewModelBase);
void MoveBlockToBottom(IItemFilterBlockViewModelBase targetBlockViewModelBase);
}
internal class ItemFilterScriptViewModel : PaneViewModel, IItemFilterScriptViewModel
{
private static readonly Logger Logger = LogManager.GetCurrentClassLogger();
private readonly IItemFilterBlockViewModelFactory _itemFilterBlockViewModelFactory;
private readonly IItemFilterBlockBaseViewModelFactory _itemFilterBlockBaseViewModelFactory;
private readonly IItemFilterBlockTranslator _blockTranslator;
private readonly IItemFilterCommentBlockViewModelFactory _itemFilterCommentBlockViewModelFactory;
private readonly IAvalonDockWorkspaceViewModel _avalonDockWorkspaceViewModel;
private readonly IItemFilterPersistenceService _persistenceService;
private readonly IMessageBoxService _messageBoxService;
@@ -86,19 +94,18 @@ namespace Filtration.ViewModels
private readonly ObservableCollection<IItemFilterBlockViewModelBase> _itemFilterBlockViewModels;
private ICollectionView _itemFilterBlockViewModelsCollectionView;
private Predicate<IItemFilterBlockViewModel> _blockFilterPredicate;
private ICommandManager _scriptCommandManager;
public ItemFilterScriptViewModel(IItemFilterBlockViewModelFactory itemFilterBlockViewModelFactory,
public ItemFilterScriptViewModel(IItemFilterBlockBaseViewModelFactory itemFilterBlockBaseViewModelFactory,
IItemFilterBlockTranslator blockTranslator,
IItemFilterCommentBlockViewModelFactory itemFilterCommentBlockViewModelFactory,
IAvalonDockWorkspaceViewModel avalonDockWorkspaceViewModel,
IItemFilterPersistenceService persistenceService,
IMessageBoxService messageBoxService,
IClipboardService clipboardService,
IBlockGroupHierarchyBuilder blockGroupHierarchyBuilder)
{
_itemFilterBlockViewModelFactory = itemFilterBlockViewModelFactory;
_itemFilterBlockBaseViewModelFactory = itemFilterBlockBaseViewModelFactory;
_blockTranslator = blockTranslator;
_itemFilterCommentBlockViewModelFactory = itemFilterCommentBlockViewModelFactory;
_avalonDockWorkspaceViewModel = avalonDockWorkspaceViewModel;
_avalonDockWorkspaceViewModel.ActiveDocumentChanged += OnActiveDocumentChanged;
_persistenceService = persistenceService;
@@ -116,12 +123,12 @@ namespace Filtration.ViewModels
ClearFilterCommand = new RelayCommand(OnClearFilterCommand, () => BlockFilterPredicate != null);
CloseCommand = new RelayCommand(async () => await OnCloseCommand());
DeleteBlockCommand = new RelayCommand(OnDeleteBlockCommand, () => SelectedBlockViewModel != null);
MoveBlockToTopCommand = new RelayCommand(OnMoveBlockToTopCommand, () => SelectedBlockViewModel != null);
MoveBlockUpCommand = new RelayCommand(OnMoveBlockUpCommand, () => SelectedBlockViewModel != null);
MoveBlockDownCommand = new RelayCommand(OnMoveBlockDownCommand, () => SelectedBlockViewModel != null);
MoveBlockToBottomCommand = new RelayCommand(OnMoveBlockToBottomCommand, () => SelectedBlockViewModel != null);
MoveBlockToTopCommand = new RelayCommand(OnMoveBlockToTopCommand, () => SelectedBlockViewModel != null && ItemFilterBlockViewModels.IndexOf(SelectedBlockViewModel) > 0);
MoveBlockUpCommand = new RelayCommand(OnMoveBlockUpCommand, () => SelectedBlockViewModel != null && ItemFilterBlockViewModels.IndexOf(SelectedBlockViewModel) > 0);
MoveBlockDownCommand = new RelayCommand(OnMoveBlockDownCommand, () => SelectedBlockViewModel != null && ItemFilterBlockViewModels.IndexOf(SelectedBlockViewModel) < ItemFilterBlockViewModels.Count);
MoveBlockToBottomCommand = new RelayCommand(OnMoveBlockToBottomCommand, () => SelectedBlockViewModel != null && ItemFilterBlockViewModels.IndexOf(SelectedBlockViewModel) < ItemFilterBlockViewModels.Count);
AddBlockCommand = new RelayCommand(OnAddBlockCommand);
AddSectionCommand = new RelayCommand(OnAddSectionCommand, () => SelectedBlockViewModel != null);
AddSectionCommand = new RelayCommand(OnAddCommentBlockCommand, () => SelectedBlockViewModel != null);
DisableBlockCommand = new RelayCommand(OnDisableBlockCommand, HasSelectedEnabledBlock);
EnableBlockCommand = new RelayCommand(OnEnableBlockCommand, HasSelectedDisabledBlock);
CopyBlockCommand = new RelayCommand(OnCopyBlockCommand, () => SelectedBlockViewModel != null);
@@ -138,6 +145,94 @@ namespace Filtration.ViewModels
IconSource = icon;
}
public void Initialise(IItemFilterScript itemFilterScript, bool newScript)
{
ItemFilterBlockViewModels.Clear();
Script = itemFilterScript;
_scriptCommandManager = Script.CommandManager;
AddItemFilterBlockViewModels(Script.ItemFilterBlocks, -1);
Script.ItemFilterBlocks.CollectionChanged += ItemFilterBlocksOnCollectionChanged;
_filenameIsFake = newScript;
if (newScript)
{
Script.FilePath = "Untitled.filter";
}
Title = Filename;
ContentId = "ScriptContentId";
}
private void ItemFilterBlocksOnCollectionChanged(object sender, NotifyCollectionChangedEventArgs notifyCollectionChangedEventArgs)
{
switch (notifyCollectionChangedEventArgs.Action)
{
case NotifyCollectionChangedAction.Add:
{
AddItemFilterBlockViewModels(notifyCollectionChangedEventArgs.NewItems.Cast<IItemFilterBlockBase>(), notifyCollectionChangedEventArgs.NewStartingIndex);
break;
}
case NotifyCollectionChangedAction.Remove:
{
RemoveItemFilterBlockviewModels(notifyCollectionChangedEventArgs.OldItems.Cast<IItemFilterBlockBase>());
break;
}
default:
{
Debugger.Break(); // Unhandled NotifyCollectionChangedAction
break;
}
}
}
private void AddItemFilterBlockViewModels(IEnumerable<IItemFilterBlockBase> itemFilterBlocks, int addAtIndex)
{
var firstNewViewModel = true;
foreach (var itemFilterBlock in itemFilterBlocks)
{
var vm = _itemFilterBlockBaseViewModelFactory.Create(itemFilterBlock);
vm.Initialise(itemFilterBlock, this);
vm.BlockBecameDirty += OnBlockBecameDirty;
if (addAtIndex == -1)
{
ItemFilterBlockViewModels.Add(vm);
}
else
{
ItemFilterBlockViewModels.Insert(addAtIndex, vm);
}
if (firstNewViewModel)
{
SelectedBlockViewModel = vm;
firstNewViewModel = false;
}
}
}
private void RemoveItemFilterBlockviewModels(IEnumerable<IItemFilterBlockBase> itemFilterBlocks)
{
foreach (var itemFilterBlock in itemFilterBlocks)
{
var itemFilterBlockViewModel = ItemFilterBlockViewModels.FirstOrDefault(f => f.BaseBlock == itemFilterBlock);
if (itemFilterBlockViewModel == null)
{
throw new InvalidOperationException("Item Filter Block removed from model but does not exist in view model!");
}
ItemFilterBlockViewModels.Remove(itemFilterBlockViewModel);
if (SelectedBlockViewModel == itemFilterBlockViewModel)
{
SelectedBlockViewModel = null;
}
}
}
public RelayCommand<bool> ToggleShowAdvancedCommand { get; }
public RelayCommand ClearFilterCommand { get; }
public RelayCommand CloseCommand { get; }
@@ -229,12 +324,7 @@ namespace Filtration.ViewModels
public string Description
{
get => Script.Description;
set
{
Script.Description = value;
IsDirty = true;
RaisePropertyChanged();
}
set => _scriptCommandManager.ExecuteCommand(new SetScriptDescriptionCommand(Script, value));
}
public bool ShowAdvanced
@@ -340,54 +430,7 @@ namespace Filtration.ViewModels
private bool _filenameIsFake;
private bool _showAdvanced;
public void Initialise(IItemFilterScript itemFilterScript, bool newScript)
{
ItemFilterBlockViewModels.Clear();
Script = itemFilterScript;
foreach (var block in Script.ItemFilterBlocks)
{
var itemFilterBlock = block as IItemFilterBlock;
if (itemFilterBlock != null)
{
var itemFilterBlockViewModel = _itemFilterBlockViewModelFactory.Create();
itemFilterBlockViewModel.Initialise(itemFilterBlock, this);
itemFilterBlockViewModel.BlockBecameDirty += OnBlockBecameDirty;
ItemFilterBlockViewModels.Add(itemFilterBlockViewModel);
continue;
}
var itemFilterCommentBlock = block as IItemFilterCommentBlock;
if (itemFilterCommentBlock == null)
{
throw new InvalidOperationException("Unknown item filter block type");
}
var itemFilterCommentBlockViewModel = _itemFilterCommentBlockViewModelFactory.Create();
itemFilterCommentBlockViewModel.Initialise(itemFilterCommentBlock);
itemFilterCommentBlockViewModel.BlockBecameDirty += OnBlockBecameDirty;
ItemFilterBlockViewModels.Add(itemFilterCommentBlockViewModel);
}
_filenameIsFake = newScript;
if (newScript)
{
Script.FilePath = "Untitled.filter";
}
if (ItemFilterBlockViewModels.Count > 0)
{
SelectedBlockViewModel = ItemFilterBlockViewModels.First();
}
Title = Filename;
ContentId = "ScriptContentId";
}
public async Task SaveAsync()
{
if (!ValidateScript()) return;
@@ -602,8 +645,7 @@ namespace Filtration.ViewModels
}
catch
{
_messageBoxService.Show("Clipboard Error", "Failed to access the clipboard, copy command not completed.",
MessageBoxButton.OK, MessageBoxImage.Error);
_messageBoxService.Show("Clipboard Error", "Failed to access the clipboard, copy command not completed.", MessageBoxButton.OK, MessageBoxImage.Error);
}
}
@@ -671,39 +713,18 @@ namespace Filtration.ViewModels
{
var clipboardText = _clipboardService.GetClipboardText();
if (string.IsNullOrEmpty(clipboardText)) return;
_blockGroupHierarchyBuilder.Initialise(Script.ItemFilterBlockGroups.First());
var translatedBlock = _blockTranslator.TranslateStringToItemFilterBlock(clipboardText, Script.ItemFilterScriptSettings);
var translatedBlock = _blockTranslator.TranslateStringToItemFilterBlock(clipboardText, Script, true); // TODO: Doesn't handle pasting comment blocks?
if (translatedBlock == null) return;
var vm = _itemFilterBlockViewModelFactory.Create();
vm.Initialise(translatedBlock, this);
if (ItemFilterBlockViewModels.Count > 0)
{
Script.ItemFilterBlocks.Insert(Script.ItemFilterBlocks.IndexOf(targetBlockViewModelBase.BaseBlock) + 1,
translatedBlock);
ItemFilterBlockViewModels.Insert(ItemFilterBlockViewModels.IndexOf(targetBlockViewModelBase) + 1, vm);
}
else
{
Script.ItemFilterBlocks.Add(translatedBlock);
ItemFilterBlockViewModels.Add(vm);
}
vm.BlockBecameDirty += OnBlockBecameDirty;
SelectedBlockViewModel = vm;
IsDirty = true;
_scriptCommandManager.ExecuteCommand(new PasteBlockCommand(Script, translatedBlock, targetBlockViewModelBase.BaseBlock));
}
catch (Exception e)
{
Logger.Error(e);
var innerException = e.InnerException?.Message ?? string.Empty;
_messageBoxService.Show("Paste Error",
e.Message + Environment.NewLine + innerException, MessageBoxButton.OK,
MessageBoxImage.Error);
_messageBoxService.Show("Paste Error", e.Message + Environment.NewLine + innerException, MessageBoxButton.OK, MessageBoxImage.Error);
}
}
@@ -712,21 +733,6 @@ namespace Filtration.ViewModels
MoveBlockToTop(SelectedBlockViewModel);
}
public void MoveBlockToTop(IItemFilterBlockViewModelBase targetBlockViewModelBase)
{
var currentIndex = ItemFilterBlockViewModels.IndexOf(targetBlockViewModelBase);
if (currentIndex > 0)
{
var block = targetBlockViewModelBase.BaseBlock;
Script.ItemFilterBlocks.Remove(block);
Script.ItemFilterBlocks.Insert(0, block);
ItemFilterBlockViewModels.Move(currentIndex, 0);
IsDirty = true;
RaisePropertyChanged(nameof(ItemFilterCommentBlockViewModels));
}
}
private void OnMoveBlockUpCommand()
{
MoveBlockUp(SelectedBlockViewModel);
@@ -734,18 +740,7 @@ namespace Filtration.ViewModels
public void MoveBlockUp(IItemFilterBlockViewModelBase targetBlockViewModelBase)
{
var currentIndex = ItemFilterBlockViewModels.IndexOf(targetBlockViewModelBase);
if (currentIndex > 0)
{
var block = targetBlockViewModelBase.BaseBlock;
var blockPos = Script.ItemFilterBlocks.IndexOf(block);
Script.ItemFilterBlocks.RemoveAt(blockPos);
Script.ItemFilterBlocks.Insert(blockPos - 1, block);
ItemFilterBlockViewModels.Move(currentIndex, currentIndex - 1);
IsDirty = true;
RaisePropertyChanged(nameof(ItemFilterCommentBlockViewModels));
}
_scriptCommandManager.ExecuteCommand(new MoveBlockUpCommand(Script, targetBlockViewModelBase?.BaseBlock));
}
private void OnMoveBlockDownCommand()
@@ -755,18 +750,7 @@ namespace Filtration.ViewModels
public void MoveBlockDown(IItemFilterBlockViewModelBase targetBlockViewModelBase)
{
var currentIndex = ItemFilterBlockViewModels.IndexOf(targetBlockViewModelBase);
if (currentIndex < ItemFilterBlockViewModels.Count - 1)
{
var block = targetBlockViewModelBase.BaseBlock;
var blockPos = Script.ItemFilterBlocks.IndexOf(block);
Script.ItemFilterBlocks.RemoveAt(blockPos);
Script.ItemFilterBlocks.Insert(blockPos + 1, block);
ItemFilterBlockViewModels.Move(currentIndex, currentIndex + 1);
IsDirty = true;
RaisePropertyChanged(nameof(ItemFilterCommentBlockViewModels));
}
_scriptCommandManager.ExecuteCommand(new MoveBlockDownCommand(Script, targetBlockViewModelBase?.BaseBlock));
}
private void OnMoveBlockToBottomCommand()
@@ -774,21 +758,6 @@ namespace Filtration.ViewModels
MoveBlockToBottom(SelectedBlockViewModel);
}
public void MoveBlockToBottom(IItemFilterBlockViewModelBase targetBlockViewModelBase)
{
var currentIndex = ItemFilterBlockViewModels.IndexOf(targetBlockViewModelBase);
if (currentIndex < ItemFilterBlockViewModels.Count - 1)
{
var block = targetBlockViewModelBase.BaseBlock;
Script.ItemFilterBlocks.Remove(block);
Script.ItemFilterBlocks.Add(block);
ItemFilterBlockViewModels.Move(currentIndex, ItemFilterBlockViewModels.Count - 1);
IsDirty = true;
RaisePropertyChanged(nameof(ItemFilterCommentBlockViewModels));
}
}
private void OnAddBlockCommand()
{
AddBlock(SelectedBlockViewModel);
@@ -796,25 +765,28 @@ namespace Filtration.ViewModels
public void AddBlock(IItemFilterBlockViewModelBase targetBlockViewModelBase)
{
var vm = _itemFilterBlockViewModelFactory.Create();
var newBlock = new ItemFilterBlock();
vm.Initialise(newBlock, this);
_scriptCommandManager.ExecuteCommand(new AddBlockCommand(Script, targetBlockViewModelBase?.BaseBlock));
// TODO: Expand new viewmodel
}
if (targetBlockViewModelBase != null)
{
Script.ItemFilterBlocks.Insert(Script.ItemFilterBlocks.IndexOf(targetBlockViewModelBase.BaseBlock) + 1, newBlock);
ItemFilterBlockViewModels.Insert(ItemFilterBlockViewModels.IndexOf(targetBlockViewModelBase) + 1, vm);
}
else
{
Script.ItemFilterBlocks.Add(newBlock);
ItemFilterBlockViewModels.Add(vm);
}
public void AddCommentBlock(IItemFilterBlockViewModelBase targetBlockViewModelBase)
{
_scriptCommandManager.ExecuteCommand(new AddCommentBlockCommand(Script, targetBlockViewModelBase.BaseBlock));
}
vm.BlockBecameDirty += OnBlockBecameDirty;
SelectedBlockViewModel = vm;
vm.IsExpanded = true;
IsDirty = true;
public void DeleteBlock(IItemFilterBlockViewModelBase targetBlockViewModelBase)
{
_scriptCommandManager.ExecuteCommand(new RemoveBlockCommand(Script, targetBlockViewModelBase.BaseBlock));
}
public void MoveBlockToBottom(IItemFilterBlockViewModelBase targetBlockViewModelBase)
{
_scriptCommandManager.ExecuteCommand(new MoveBlockToBottomCommand(Script, targetBlockViewModelBase.BaseBlock));
}
public void MoveBlockToTop(IItemFilterBlockViewModelBase targetBlockViewModelBase)
{
_scriptCommandManager.ExecuteCommand(new MoveBlockToTopCommand(Script, targetBlockViewModelBase.BaseBlock));
}
private void OnBlockBecameDirty(object sender, EventArgs e)
@@ -822,23 +794,9 @@ namespace Filtration.ViewModels
SetDirtyFlag();
}
private void OnAddSectionCommand()
private void OnAddCommentBlockCommand()
{
AddSection(SelectedBlockViewModel);
}
public void AddSection(IItemFilterBlockViewModelBase targetBlockViewModelBase)
{
var vm = _itemFilterCommentBlockViewModelFactory.Create();
var newSection = new ItemFilterCommentBlock { Comment = "New Comment Block" };
vm.Initialise(newSection);
Script.ItemFilterBlocks.Insert(Script.ItemFilterBlocks.IndexOf(targetBlockViewModelBase.BaseBlock), newSection);
ItemFilterBlockViewModels.Insert(ItemFilterBlockViewModels.IndexOf(targetBlockViewModelBase), vm);
IsDirty = true;
SelectedBlockViewModel = vm;
RaisePropertyChanged(nameof(ItemFilterCommentBlockViewModels));
Messenger.Default.Send(new NotificationMessage("SectionsChanged"));
AddCommentBlock(SelectedBlockViewModel);
}
private void OnExpandAllBlocksCommand()
@@ -862,31 +820,6 @@ namespace Filtration.ViewModels
DeleteBlock(SelectedBlockViewModel);
}
public void DeleteBlock(IItemFilterBlockViewModelBase targetBlockViewModelBase)
{
var result = _messageBoxService.Show("Delete Confirmation", "Are you sure you wish to delete this block?",
MessageBoxButton.YesNo,
MessageBoxImage.Question);
if (result == MessageBoxResult.Yes)
{
var isSection = targetBlockViewModelBase.BaseBlock is ItemFilterCommentBlock;
Script.ItemFilterBlocks.Remove(targetBlockViewModelBase.BaseBlock);
ItemFilterBlockViewModels.Remove(targetBlockViewModelBase);
IsDirty = true;
targetBlockViewModelBase.BlockBecameDirty -= OnBlockBecameDirty;
if (isSection)
{
Messenger.Default.Send(new NotificationMessage("SectionsChanged"));
}
}
SelectedBlockViewModel = null;
}
private void OnDisableBlockCommand()
{
var selectedBlockViewModel = SelectedBlockViewModel as IItemFilterBlockViewModel;

View File

@@ -85,6 +85,11 @@ namespace Filtration.ViewModels
PasteCommand = new RelayCommand(OnPasteCommand, () => ActiveDocumentIsScript && ActiveScriptHasSelectedBlock);
PasteBlockStyleCommand = new RelayCommand(OnPasteBlockStyleCommand, () => ActiveDocumentIsScript && ActiveScriptHasSelectedBlock);
// TODO: Only enabled if undo/redo available
UndoCommand = new RelayCommand(OnUndoCommand, () => ActiveDocumentIsScript);
RedoCommand = new RelayCommand(OnRedoCommand, () => ActiveDocumentIsScript);
MoveBlockUpCommand = new RelayCommand(OnMoveBlockUpCommand, () => ActiveDocumentIsScript && ActiveScriptHasSelectedBlock);
MoveBlockDownCommand = new RelayCommand(OnMoveBlockDownCommand, () => ActiveDocumentIsScript && ActiveScriptHasSelectedBlock);
MoveBlockToTopCommand = new RelayCommand(OnMoveBlockToTopCommand, () => ActiveDocumentIsScript && ActiveScriptHasSelectedBlock);
@@ -158,9 +163,7 @@ namespace Filtration.ViewModels
}
case "OpenScript":
{
#pragma warning disable 4014
Task.Run(OnOpenScriptCommand).GetAwaiter().GetResult();
#pragma warning restore 4014
OnOpenScriptCommand();
break;
}
case "ShowLoadingBanner":
@@ -191,6 +194,9 @@ namespace Filtration.ViewModels
public RelayCommand OpenAboutWindowCommand { get; }
public RelayCommand ReplaceColorsCommand { get; }
public RelayCommand UndoCommand { get;}
public RelayCommand RedoCommand { get; }
public RelayCommand EditMasterThemeCommand { get; }
public RelayCommand CreateThemeCommand { get; }
public RelayCommand ApplyThemeToScriptCommand { get; }
@@ -521,6 +527,16 @@ namespace Filtration.ViewModels
_avalonDockWorkspaceViewModel.ActiveScriptViewModel.PasteBlockStyleCommand.Execute(null);
}
private void OnUndoCommand()
{
_avalonDockWorkspaceViewModel.ActiveScriptViewModel.Script.CommandManager.Undo();
}
private void OnRedoCommand()
{
_avalonDockWorkspaceViewModel.ActiveScriptViewModel.Script.CommandManager.Redo();
}
private void OnNewScriptCommand()
{
var newViewModel = _itemFilterScriptRepository.NewScript();

View File

@@ -30,6 +30,8 @@
<Image Source="/Filtration;component/Resources/Icons/PasteStyle.ico" x:Key="PasteStyleIcon" x:Shared="False" />
<Image Source="/Filtration;component/Resources/Icons/filtration_icon.png" x:Key="FiltrationIcon" x:Shared="False" />
<Image Source="/Filtration;component/Resources/Icons/Add.ico" x:Key="AddIcon" x:Shared="False" />
<Image Source="/Filtration;component/Resources/Icons/undo_icon.png" x:Key="UndoIcon" x:Shared="False" />
<Image Source="/Filtration;component/Resources/Icons/redo_icon.png" x:Key="RedoIcon" x:Shared="False" />
<Image Source="/Filtration;component/Resources/Icons/ThemeComponentDelete.ico" x:Key="ThemeComponentDeleteIcon" x:Shared="False" />
<Image Source="/Filtration;component/Resources/Icons/standby_enabled_icon.png" x:Key="StandbyEnabledIcon" x:Shared="False" />
<Image Source="/Filtration;component/Resources/Icons/standby_disabled_icon.png" x:Key="StandbyDisabledIcon" x:Shared="False" />

View File

@@ -19,6 +19,10 @@
<KeyBinding Command="{Binding SaveCommand}" Modifiers="Control" Key="S" />
<KeyBinding Command="{Binding OpenScriptCommand}" Modifiers="Control" Key="O" />
<KeyBinding Command="{Binding NewScriptCommand}" Modifiers="Control" Key="N" />
<!-- Undo/Redo support incomplete -->
<!--<KeyBinding Command="{Binding UndoCommand}" Modifiers="Control" Key="Z" />
<KeyBinding Command="{Binding RedoCommand}" Modifiers="Control" Key="Y" />-->
</fluent:RibbonWindow.InputBindings>
<utility:RoutedCommandHandlers.Commands>
<utility:RoutedCommandHandler RoutedCommand="{StaticResource OpenScriptRoutedCommand}" Command="{Binding OpenScriptCommand}" />
@@ -32,7 +36,7 @@
<fluent:BackstageTabItem.ContentTemplate>
<DataTemplate>
<StackPanel>
<TextBlock Margin="20">Recent Documents will go here in a future release.</TextBlock>
<TextBlock Margin="20">Recent Documents will go here in a future release.</TextBlock>
</StackPanel>
</DataTemplate>
</fluent:BackstageTabItem.ContentTemplate>
@@ -85,6 +89,12 @@
<fluent:Button Header="Paste Style" Command="{Binding PasteBlockStyleCommand}" Icon="{StaticResource PasteStyleIcon}" LargeIcon="{StaticResource PasteIcon}" SizeDefinition="Middle" ToolTip="Paste Style (Ctrl+Shift+V)" />
<fluent:Button Header="Copy Script" Command="{Binding CopyScriptCommand}" Icon="{StaticResource CopyIcon}" LargeIcon="{StaticResource PasteIcon}" SizeDefinition="Middle" />
</fluent:RibbonGroupBox>
<!-- Undo/Redo support incomplete -->
<!--<fluent:RibbonGroupBox Header="Undo">
<fluent:Button Header="Undo" Command="{Binding UndoCommand}" ToolTip="Undo" SizeDefinition="Middle" Icon="{StaticResource UndoIcon}" />
<fluent:Button Header="Redo" Command="{Binding RedoCommand}" ToolTip="Redo" SizeDefinition="Middle" Icon="{StaticResource RedoIcon}" />
</fluent:RibbonGroupBox>-->
<fluent:RibbonGroupBox Header="Blocks">
<fluent:Button Header="Add Block" Command="{Binding AddBlockCommand}" SizeDefinition="Middle" Icon="{StaticResource AddBlockIcon}" />
<fluent:Button Header="Add Section" Command="{Binding AddSectionCommand}" SizeDefinition="Middle" Icon="{StaticResource AddSectionIcon}" />

View File

@@ -3,6 +3,7 @@ using Castle.MicroKernel.Registration;
using Castle.MicroKernel.SubSystems.Configuration;
using Castle.Windsor;
using Filtration.ViewModels;
using Filtration.ViewModels.Factories;
using Filtration.ViewModels.ToolPanes;
namespace Filtration.WindsorInstallers
@@ -79,6 +80,11 @@ namespace Filtration.WindsorInstallers
container.Register(
Component.For<IItemFilterScriptViewModelFactory>().AsFactory());
container.Register(
Component.For<IItemFilterBlockBaseViewModelFactory>()
.ImplementedBy<ItemFilterBlockBaseViewModelFactory>()
.LifeStyle.Singleton);
}
}
}