Skip to content

Commit 213bf1c

Browse files
committed
Fix handling of cancellation in CE move to folder commands
They did not catch the corresponding refactoring exception since the user interaction was not contained in the try-catch-block. This also adds a user notification in case one of the affected modules is stale.
1 parent f0cbd16 commit 213bf1c

File tree

6 files changed

+55
-21
lines changed

6 files changed

+55
-21
lines changed

Rubberduck.Core/UI/CodeExplorer/Commands/Abstract/CodeExplorerMoveToFolderCommandBase.cs

Lines changed: 39 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -23,24 +23,27 @@ public abstract class CodeExplorerMoveToFolderCommandBase : CodeExplorerCommandB
2323
};
2424

2525
private readonly IParserStatusProvider _parserStatusProvider;
26+
private readonly RubberduckParserState _state;
2627

2728
private readonly IRefactoringAction<MoveMultipleFoldersModel> _moveFolders;
2829
private readonly IRefactoringAction<MoveMultipleToFolderModel> _moveToFolder;
2930

3031
private readonly IRefactoringFailureNotifier _failureNotifier;
3132

32-
public CodeExplorerMoveToFolderCommandBase(
33+
protected CodeExplorerMoveToFolderCommandBase(
3334
MoveMultipleFoldersRefactoringAction moveFolders,
3435
MoveMultipleToFolderRefactoringAction moveToFolder,
3536
MoveToFolderRefactoringFailedNotifier failureNotifier,
3637
IParserStatusProvider parserStatusProvider,
37-
IVbeEvents vbeEvents)
38+
IVbeEvents vbeEvents,
39+
RubberduckParserState state)
3840
: base(vbeEvents)
3941
{
4042
_moveFolders = moveFolders;
4143
_moveToFolder = moveToFolder;
4244

4345
_parserStatusProvider = parserStatusProvider;
46+
_state = state;
4447
_failureNotifier = failureNotifier;
4548

4649
AddToCanExecuteEvaluation(SpecialEvaluateCanExecute);
@@ -67,15 +70,13 @@ protected override void OnExecute(object parameter)
6770
if (node is CodeExplorerComponentViewModel componentViewModel)
6871
{
6972
var model = ComponentModel(componentViewModel);
70-
var modifiedModel = ModifiedComponentModel(model, parameter);
71-
ExecuteRefactoringAction(modifiedModel, _moveToFolder, _failureNotifier);
73+
ExecuteRefactoringAction(model, parameter, ValidateInitialComponentModel, ModifiedComponentModel, _moveToFolder, _failureNotifier);
7274
}
7375

7476
if (node is CodeExplorerCustomFolderViewModel folderViewModel)
7577
{
7678
var model = FolderModel(folderViewModel);
77-
var modifiedModel = ModifiedFolderModel(model, parameter);
78-
ExecuteRefactoringAction(modifiedModel, _moveFolders, _failureNotifier);
79+
ExecuteRefactoringAction(model, parameter, ValidateInitialFolderModel, ModifiedFolderModel, _moveFolders, _failureNotifier);
7980
}
8081
}
8182

@@ -103,6 +104,17 @@ private static ICollection<ModuleDeclaration> ContainedModules(ICodeExplorerNode
103104
.ToList();
104105
}
105106

107+
private void ValidateInitialFolderModel(MoveMultipleFoldersModel model)
108+
{
109+
var firstStaleAffectedModules = model.ModulesBySourceFolder.Values
110+
.SelectMany(modules => modules)
111+
.FirstOrDefault(module => _state.IsNewOrModified(module.QualifiedModuleName));
112+
if (firstStaleAffectedModules != null)
113+
{
114+
throw new AffectedModuleIsStaleException(firstStaleAffectedModules.QualifiedModuleName);
115+
}
116+
}
117+
106118
private MoveMultipleToFolderModel ComponentModel(CodeExplorerComponentViewModel componentViewModel)
107119
{
108120
if (!(componentViewModel.Declaration is ModuleDeclaration moduleDeclaration))
@@ -113,14 +125,32 @@ private MoveMultipleToFolderModel ComponentModel(CodeExplorerComponentViewModel
113125
var targets = new List<ModuleDeclaration>{moduleDeclaration};
114126
var targetFolder = moduleDeclaration.CustomFolder;
115127
return new MoveMultipleToFolderModel(targets, targetFolder);
116-
}
128+
}
129+
130+
private void ValidateInitialComponentModel(MoveMultipleToFolderModel model)
131+
{
132+
var firstStaleAffectedModules = model.Targets
133+
.FirstOrDefault(module => _state.IsNewOrModified(module.QualifiedModuleName));
134+
if (firstStaleAffectedModules != null)
135+
{
136+
throw new AffectedModuleIsStaleException(firstStaleAffectedModules.QualifiedModuleName);
137+
}
138+
}
117139

118-
private static void ExecuteRefactoringAction<TModel>(TModel model, IRefactoringAction<TModel> refactoringAction, IRefactoringFailureNotifier failureNotifier)
140+
private static void ExecuteRefactoringAction<TModel>(
141+
TModel model,
142+
object parameter,
143+
Action<TModel> initialModelValidation,
144+
Func<TModel,object,TModel> modelModification,
145+
IRefactoringAction<TModel> refactoringAction,
146+
IRefactoringFailureNotifier failureNotifier)
119147
where TModel : class, IRefactoringModel
120148
{
121149
try
122150
{
123-
refactoringAction.Refactor(model);
151+
initialModelValidation(model);
152+
var modifiedModel = modelModification(model, parameter);
153+
refactoringAction.Refactor(modifiedModel);
124154
}
125155
catch (RefactoringAbortedException)
126156
{}

Rubberduck.Core/UI/CodeExplorer/Commands/CodeExplorerMoveToFolderCommand.cs

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -24,8 +24,9 @@ public CodeExplorerMoveToFolderCommand(
2424
RefactoringUserInteraction<IMoveMultipleToFolderPresenter, MoveMultipleToFolderModel> moveToFolderInteraction,
2525
MoveToFolderRefactoringFailedNotifier failureNotifier,
2626
IParserStatusProvider parserStatusProvider,
27-
IVbeEvents vbeEvents)
28-
: base(moveFolders, moveToFolder, failureNotifier, parserStatusProvider, vbeEvents)
27+
IVbeEvents vbeEvents,
28+
RubberduckParserState state)
29+
: base(moveFolders, moveToFolder, failureNotifier, parserStatusProvider, vbeEvents, state)
2930
{
3031
_moveFoldersInteraction = moveFoldersInteraction;
3132
_moveToFolderInteraction = moveToFolderInteraction;

Rubberduck.Core/UI/CodeExplorer/Commands/DragAndDrop/CodeExplorerMoveToFolderDragAndDropCommand.cs

Lines changed: 9 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@
66
using Rubberduck.Navigation.CodeExplorer;
77
using Rubberduck.Parsing.Symbols;
88
using Rubberduck.Parsing.VBA;
9+
using Rubberduck.Refactorings.Exceptions;
910
using Rubberduck.Refactorings.MoveFolder;
1011
using Rubberduck.Refactorings.MoveToFolder;
1112
using Rubberduck.Resources;
@@ -27,8 +28,9 @@ public CodeExplorerMoveToFolderDragAndDropCommand(
2728
IParserStatusProvider parserStatusProvider,
2829
IVbeEvents vbeEvents,
2930
IMessageBox messageBox,
30-
IDeclarationFinderProvider declarationFinderProvider)
31-
: base(moveFolders, moveToFolder, failureNotifier, parserStatusProvider, vbeEvents)
31+
IDeclarationFinderProvider declarationFinderProvider,
32+
RubberduckParserState state)
33+
: base(moveFolders, moveToFolder, failureNotifier, parserStatusProvider, vbeEvents, state)
3234
{
3335
_declarationFinderProvider = declarationFinderProvider;
3436
_messageBox = messageBox;
@@ -69,6 +71,11 @@ protected override MoveMultipleFoldersModel ModifiedFolderModel(MoveMultipleFold
6971
{
7072
model.TargetFolder = targetFolder;
7173
}
74+
else
75+
{
76+
throw new RefactoringAbortedException();
77+
}
78+
7279
return model;
7380
}
7481

Rubberduck.Core/UI/Command/Refactorings/Notifiers/MoveContainingFolderRefactoringFailedNotifier.cs

Lines changed: 0 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -26,10 +26,6 @@ protected override string Message(RefactoringException exception)
2626
DeclarationType.Module);
2727
case NoTargetFolderException noTargetFolder:
2828
return Resources.RubberduckUI.RefactoringFailure_NoTargetFolder;
29-
case AffectedModuleIsStaleException affectedModuleIsStale:
30-
return string.Format(
31-
Resources.RubberduckUI.RefactoringFailure_AffectedModuleIsStale,
32-
affectedModuleIsStale.StaleModule.ToString());
3329
default:
3430
return base.Message(exception);
3531
}

Rubberduck.Core/UI/Command/Refactorings/Notifiers/MoveToFolderRefactoringFailedNotifier.cs

Lines changed: 0 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -26,10 +26,6 @@ protected override string Message(RefactoringException exception)
2626
DeclarationType.Module);
2727
case NoTargetFolderException noTargetFolder:
2828
return Resources.RubberduckUI.RefactoringFailure_NoTargetFolder;
29-
case AffectedModuleIsStaleException affectedModuleIsStale:
30-
return string.Format(
31-
Resources.RubberduckUI.RefactoringFailure_AffectedModuleIsStale,
32-
affectedModuleIsStale.StaleModule.ToString());
3329
default:
3430
return base.Message(exception);
3531
}

Rubberduck.Core/UI/Command/Refactorings/Notifiers/RefactoringFailureNotifierBase.cs

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -44,6 +44,10 @@ protected virtual string Message(RefactoringException exception)
4444
case SuspendParserFailureException suspendParserFailure:
4545
Logger.Warn(suspendParserFailure);
4646
return Resources.RubberduckUI.RefactoringFailure_SuspendParserFailure;
47+
case AffectedModuleIsStaleException affectedModuleIsStale:
48+
return string.Format(
49+
Resources.RubberduckUI.RefactoringFailure_AffectedModuleIsStale,
50+
affectedModuleIsStale.StaleModule.ToString());
4751
default:
4852
Logger.Error(exception);
4953
return string.Empty;

0 commit comments

Comments
 (0)