Skip to content

Commit

Permalink
Enhance CE Rename command to cover folder renames
Browse files Browse the repository at this point in the history
It incorporates a new RenameFolderCommand.
  • Loading branch information
MDoerner committed Jun 7, 2020
1 parent a4247f9 commit 082d93e
Show file tree
Hide file tree
Showing 6 changed files with 223 additions and 6 deletions.
Original file line number Diff line number Diff line change
@@ -0,0 +1,38 @@
using Rubberduck.Parsing.VBA;
using Rubberduck.Refactorings;
using Rubberduck.UI.Command.Refactorings.Notifiers;
using Rubberduck.VBEditor.Events;

namespace Rubberduck.UI.CodeExplorer.Commands.Abstract
{
public abstract class CodeExplorerInteractiveRefactoringCommandBase<TModel> : CodeExplorerRefactoringCommandBase<TModel>
where TModel : class, IRefactoringModel
{
private readonly IRefactoringAction<TModel> _refactoringAction;
private readonly IRefactoringUserInteraction<TModel> _refactoringUserInteraction;
private readonly IRefactoringFailureNotifier _failureNotifier;

protected CodeExplorerInteractiveRefactoringCommandBase(
IRefactoringAction<TModel> refactoringAction,
IRefactoringUserInteraction<TModel> refactoringUserInteraction,
IRefactoringFailureNotifier failureNotifier,
IParserStatusProvider parserStatusProvider,
IVbeEvents vbeEvents)
: base(refactoringAction, failureNotifier, parserStatusProvider, vbeEvents)
{
_refactoringUserInteraction = refactoringUserInteraction;
_refactoringAction = refactoringAction;
_failureNotifier = failureNotifier;
}

protected abstract TModel InitialModelFromParameter(object parameter);
protected abstract void ValidateInitialModel(TModel model);

protected override TModel ModelFromParameter(object parameter)
{
var initialModel = InitialModelFromParameter(parameter);
ValidateInitialModel(initialModel);
return _refactoringUserInteraction.UserModifiedModel(initialModel);
}
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,61 @@
using Rubberduck.Parsing.VBA;
using Rubberduck.Refactorings;
using Rubberduck.Refactorings.Exceptions;
using Rubberduck.UI.Command.Refactorings.Notifiers;
using Rubberduck.VBEditor.Events;

namespace Rubberduck.UI.CodeExplorer.Commands.Abstract
{
public abstract class CodeExplorerRefactoringCommandBase<TModel> : CodeExplorerCommandBase
where TModel : class, IRefactoringModel
{
private readonly IParserStatusProvider _parserStatusProvider;

private readonly IRefactoringAction<TModel> _refactoringAction;
private readonly IRefactoringFailureNotifier _failureNotifier;

protected CodeExplorerRefactoringCommandBase(
IRefactoringAction<TModel> refactoringAction,
IRefactoringFailureNotifier failureNotifier,
IParserStatusProvider parserStatusProvider,
IVbeEvents vbeEvents)
: base(vbeEvents)
{
_refactoringAction = refactoringAction;
_failureNotifier = failureNotifier;

_parserStatusProvider = parserStatusProvider;

AddToCanExecuteEvaluation(SpecialEvaluateCanExecute);
}

private bool SpecialEvaluateCanExecute(object parameter)
{
return _parserStatusProvider.Status == ParserState.Ready;
}

protected abstract TModel ModelFromParameter(object parameter);
protected abstract void ValidateModel(TModel model);

protected override void OnExecute(object parameter)
{
if (!CanExecute(parameter))
{
return;
}

try
{
var model = ModelFromParameter(parameter);
ValidateModel(model);
_refactoringAction.Refactor(model);
}
catch (RefactoringAbortedException)
{ }
catch (RefactoringException exception)
{
_failureNotifier.Notify(exception);
}
}
}
}
28 changes: 23 additions & 5 deletions Rubberduck.Core/UI/CodeExplorer/Commands/RenameCommand.cs
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@
using Rubberduck.Refactorings;
using Rubberduck.Refactorings.Exceptions;
using Rubberduck.Refactorings.Rename;
using Rubberduck.UI.Command;
using Rubberduck.VBEditor.Events;
using Rubberduck.UI.Command.Refactorings.Notifiers;

Expand All @@ -16,23 +17,28 @@ public sealed class RenameCommand : CodeExplorerCommandBase
{
typeof(CodeExplorerProjectViewModel),
typeof(CodeExplorerComponentViewModel),
typeof(CodeExplorerMemberViewModel)
typeof(CodeExplorerMemberViewModel),
typeof(CodeExplorerCustomFolderViewModel)
};

private readonly IParserStatusProvider _parserStatusProvider;
private readonly IRefactoring _refactoring;
private readonly IRefactoringFailureNotifier _failureNotifier;

private readonly CommandBase _renameFolderCommand;

public RenameCommand(
RenameRefactoring refactoring,
RenameFailedNotifier renameFailedNotifier,
IParserStatusProvider parserStatusProvider,
IVbeEvents vbeEvents)
IVbeEvents vbeEvents,
RenameFolderCommand renameFolderCommand)
: base(vbeEvents)
{
_refactoring = refactoring;
_failureNotifier = renameFailedNotifier;
_parserStatusProvider = parserStatusProvider;
_renameFolderCommand = renameFolderCommand;

AddToCanExecuteEvaluation(SpecialEvaluateCanExecute);
}
Expand All @@ -41,14 +47,26 @@ public sealed class RenameCommand : CodeExplorerCommandBase

private bool SpecialEvaluateCanExecute(object parameter)
{
return _parserStatusProvider.Status == ParserState.Ready;
return _parserStatusProvider.Status == ParserState.Ready
&& (!(parameter is CodeExplorerCustomFolderViewModel folderModel)
|| _renameFolderCommand.CanExecute(folderModel));
}

protected override void OnExecute(object parameter)
{
if (!CanExecute(parameter) ||
!(parameter is CodeExplorerItemViewModel node) ||
node.Declaration == null)
!(parameter is CodeExplorerItemViewModel node))
{
return;
}

if (node is CodeExplorerCustomFolderViewModel folderNode)
{
_renameFolderCommand.Execute(folderNode);
return;
}

if (node.Declaration == null)
{
return;
}
Expand Down
86 changes: 86 additions & 0 deletions Rubberduck.Core/UI/CodeExplorer/Commands/RenameFolderCommand.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,86 @@
using System;
using System.Collections.Generic;
using System.Linq;
using Rubberduck.JunkDrawer.Extensions;
using Rubberduck.Navigation.CodeExplorer;
using Rubberduck.Parsing.Symbols;
using Rubberduck.Parsing.VBA;
using Rubberduck.Refactorings;
using Rubberduck.Refactorings.Exceptions;
using Rubberduck.Refactorings.RenameFolder;
using Rubberduck.UI.CodeExplorer.Commands.Abstract;
using Rubberduck.UI.Command.Refactorings.Notifiers;
using Rubberduck.VBEditor.Events;

namespace Rubberduck.UI.CodeExplorer.Commands
{
public class RenameFolderCommand : CodeExplorerInteractiveRefactoringCommandBase<RenameFolderModel>
{
private static readonly Type[] ApplicableNodes =
{
typeof(CodeExplorerCustomFolderViewModel)
};

private RubberduckParserState _state;

public RenameFolderCommand(
RenameFolderRefactoringAction refactoringAction,
RefactoringUserInteraction<IRenameFolderPresenter, RenameFolderModel> userInteraction,
RenameFolderFailedNotifier failureNotifier,
IParserStatusProvider parserStatusProvider,
IVbeEvents vbeEvents,
RubberduckParserState state)
: base(refactoringAction, userInteraction, failureNotifier, parserStatusProvider, vbeEvents)
{
_state = state;
}

public override IEnumerable<Type> ApplicableNodeTypes => ApplicableNodes;

protected override RenameFolderModel InitialModelFromParameter(object parameter)
{
if (!(parameter is CodeExplorerCustomFolderViewModel folderModel))
{
throw new ArgumentException(nameof(parameter));
}

return ModelFromNode(folderModel);
}

private static RenameFolderModel ModelFromNode(CodeExplorerCustomFolderViewModel folderModel)
{
var folder = folderModel.FullPath;
var containedModules = ContainedModules(folderModel);
var initialSubFolder = folder.SubFolderName();
return new RenameFolderModel(folder, containedModules, initialSubFolder);
}

private static ICollection<ModuleDeclaration> ContainedModules(ICodeExplorerNode itemModel)
{
if (itemModel is CodeExplorerComponentViewModel componentModel)
{
var component = componentModel.Declaration;
return component is ModuleDeclaration moduleDeclaration
? new List<ModuleDeclaration> { moduleDeclaration }
: new List<ModuleDeclaration>();
}

return itemModel.Children
.SelectMany(ContainedModules)
.ToList();
}

protected override void ValidateInitialModel(RenameFolderModel model)
{
var firstStaleAffectedModules = model.ModulesToMove
.FirstOrDefault(module => _state.IsNewOrModified(module.QualifiedModuleName));
if (firstStaleAffectedModules != null)
{
throw new AffectedModuleIsStaleException(firstStaleAffectedModules.QualifiedModuleName);
}
}

protected override void ValidateModel(RenameFolderModel model)
{ }
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
using Rubberduck.Interaction;

namespace Rubberduck.UI.Command.Refactorings.Notifiers
{
public class RenameFolderFailedNotifier : RefactoringFailureNotifierBase
{
public RenameFolderFailedNotifier(IMessageBox messageBox)
: base(messageBox)
{}

protected override string Caption => Resources.RubberduckUI.RenameDialog_Caption;
}
}
Original file line number Diff line number Diff line change
@@ -1,9 +1,10 @@
using System.Windows;
using Rubberduck.Refactorings;
using Rubberduck.Refactorings.RenameFolder;

namespace Rubberduck.UI.Refactorings.RenameFolder
{
public partial class RenameFolderView : IRefactoringView<RenameFolderView>
public partial class RenameFolderView : IRefactoringView<RenameFolderModel>
{
public RenameFolderView()
{
Expand Down

0 comments on commit 082d93e

Please sign in to comment.