Skip to content

Commit 8cde475

Browse files
committed
Introduce CodeExplorerMoveToFolderCommand
This combines MoveToFolder and MoveFolder, selecting based on the selected node of the CE. In principle, the backing refactoring actions are capable of dealing with multiple nodes at once. However, the CE only allows selecting single items at the moment and the command reflects that when deriving the models to pass to the refactoring actions.
1 parent b9e6e70 commit 8cde475

File tree

12 files changed

+173
-15
lines changed

12 files changed

+173
-15
lines changed

Rubberduck.Core/Navigation/CodeExplorer/CodeExplorerViewModel.cs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -379,6 +379,7 @@ private void ExecuteRemoveCommand(object param)
379379
public OpenProjectPropertiesCommand OpenProjectPropertiesCommand { get; set; }
380380
public SetAsStartupProjectCommand SetAsStartupProjectCommand { get; set; }
381381
public RenameCommand RenameCommand { get; set; }
382+
public CodeExplorerMoveToFolderCommand MoveToFolderCommand { get; set; }
382383
public IndentCommand IndenterCommand { get; set; }
383384
public CodeExplorerFindAllReferencesCommand FindAllReferencesCommand { get; set; }
384385
public CodeExplorerFindAllImplementationsCommand FindAllImplementationsCommand { get; set; }

Rubberduck.Core/UI/CodeExplorer/CodeExplorerControl.xaml

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -417,9 +417,12 @@
417417
<Image Source="{StaticResource RefreshImage}" />
418418
</MenuItem.Icon>
419419
</MenuItem>
420-
<MenuItem Header="{Resx ResxName=Rubberduck.Resources.RubberduckUI, Key=Rename}"
420+
<MenuItem Header="{Resx ResxName=Rubberduck.Resources.CodeExplorer.CodeExplorerUI, Key=CodeExplorer_Rename}"
421421
Command="{Binding RenameCommand}"
422422
CommandParameter="{Binding SelectedItem, Mode=OneWay}" />
423+
<MenuItem Header="{Resx ResxName=Rubberduck.Resources.CodeExplorer.CodeExplorerUI, Key=CodeExplorer_MoveToFolder}"
424+
Command="{Binding MoveToFolderCommand}"
425+
CommandParameter="{Binding SelectedItem, Mode=OneWay}" />
423426
<MenuItem Header="{Resx ResxName=Rubberduck.Resources.CodeExplorer.CodeExplorerUI, Key=CodeExplorer_ExtractInterfaceText}"
424427
Command="{Binding CodeExplorerExtractInterfaceCommand}"
425428
CommandParameter="{Binding SelectedItem, Mode=OneWay}">
Lines changed: 139 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,139 @@
1+
using System;
2+
using System.Collections.Generic;
3+
using System.Linq;
4+
using Rubberduck.JunkDrawer.Extensions;
5+
using Rubberduck.Navigation.CodeExplorer;
6+
using Rubberduck.Parsing.Symbols;
7+
using Rubberduck.Parsing.VBA;
8+
using Rubberduck.Refactorings;
9+
using Rubberduck.Refactorings.Exceptions;
10+
using Rubberduck.Refactorings.MoveFolder;
11+
using Rubberduck.Refactorings.MoveToFolder;
12+
using Rubberduck.VBEditor.Events;
13+
using Rubberduck.UI.Command.Refactorings.Notifiers;
14+
15+
namespace Rubberduck.UI.CodeExplorer.Commands
16+
{
17+
public sealed class CodeExplorerMoveToFolderCommand : CodeExplorerCommandBase
18+
{
19+
private static readonly Type[] ApplicableNodes =
20+
{
21+
typeof(CodeExplorerCustomFolderViewModel),
22+
typeof(CodeExplorerComponentViewModel)
23+
};
24+
25+
private readonly IParserStatusProvider _parserStatusProvider;
26+
27+
private readonly IRefactoringAction<MoveMultipleFoldersModel> _moveFolders;
28+
private readonly IRefactoringUserInteraction<MoveMultipleFoldersModel> _moveFoldersInteraction;
29+
30+
private readonly IRefactoringAction<MoveMultipleToFolderModel> _moveToFolder;
31+
private readonly IRefactoringUserInteraction<MoveMultipleToFolderModel> _moveToFolderInteraction;
32+
33+
private readonly IRefactoringFailureNotifier _failureNotifier;
34+
35+
public CodeExplorerMoveToFolderCommand(
36+
MoveMultipleFoldersRefactoringAction moveFolders,
37+
RefactoringUserInteraction<IMoveMultipleFoldersPresenter, MoveMultipleFoldersModel> moveFoldersInteraction,
38+
MoveMultipleToFolderRefactoringAction moveToFolder,
39+
RefactoringUserInteraction<IMoveMultipleToFolderPresenter, MoveMultipleToFolderModel> moveToFolderInteraction,
40+
MoveToFolderRefactoringFailedNotifier failureNotifier,
41+
IParserStatusProvider parserStatusProvider,
42+
IVbeEvents vbeEvents)
43+
: base(vbeEvents)
44+
{
45+
_moveFolders = moveFolders;
46+
_moveFoldersInteraction = moveFoldersInteraction;
47+
_moveToFolder = moveToFolder;
48+
_moveToFolderInteraction = moveToFolderInteraction;
49+
50+
_parserStatusProvider = parserStatusProvider;
51+
_failureNotifier = failureNotifier;
52+
53+
AddToCanExecuteEvaluation(SpecialEvaluateCanExecute);
54+
}
55+
56+
public override IEnumerable<Type> ApplicableNodeTypes => ApplicableNodes;
57+
58+
private bool SpecialEvaluateCanExecute(object parameter)
59+
{
60+
return _parserStatusProvider.Status == ParserState.Ready
61+
&& (parameter is CodeExplorerCustomFolderViewModel
62+
|| parameter is CodeExplorerComponentViewModel componentViewModel
63+
&& componentViewModel.Declaration is ModuleDeclaration);
64+
}
65+
66+
protected override void OnExecute(object parameter)
67+
{
68+
if (!CanExecute(parameter))
69+
{
70+
return;
71+
}
72+
73+
if (parameter is CodeExplorerComponentViewModel componentViewModel)
74+
{
75+
var model = ComponentModel(componentViewModel);
76+
var modifiedModel = _moveToFolderInteraction.UserModifiedModel(model);
77+
ExecuteRefactoringAction(modifiedModel, _moveToFolder, _failureNotifier);
78+
}
79+
80+
if (parameter is CodeExplorerCustomFolderViewModel folderViewModel)
81+
{
82+
var model = FolderModel(folderViewModel);
83+
var modifiedModel = _moveFoldersInteraction.UserModifiedModel(model);
84+
ExecuteRefactoringAction(modifiedModel, _moveFolders, _failureNotifier);
85+
}
86+
}
87+
88+
private MoveMultipleFoldersModel FolderModel(CodeExplorerCustomFolderViewModel folderModel)
89+
{
90+
var folder = folderModel.FullPath;
91+
var containedModules = ContainedModules(folderModel);
92+
var modulesBySourceFolder = new Dictionary<string, ICollection<ModuleDeclaration>>{{folder, containedModules}};
93+
var initialTargetFolder = folder.ParentFolder();
94+
return new MoveMultipleFoldersModel(modulesBySourceFolder, initialTargetFolder);
95+
}
96+
97+
private static ICollection<ModuleDeclaration> ContainedModules(ICodeExplorerNode itemModel)
98+
{
99+
if (itemModel is CodeExplorerComponentViewModel componentModel)
100+
{
101+
var component = componentModel.Declaration;
102+
return component is ModuleDeclaration moduleDeclaration
103+
? new List<ModuleDeclaration> {moduleDeclaration}
104+
: new List<ModuleDeclaration>();
105+
}
106+
107+
return itemModel.Children
108+
.SelectMany(ContainedModules)
109+
.ToList();
110+
}
111+
112+
private MoveMultipleToFolderModel ComponentModel(CodeExplorerComponentViewModel componentViewModel)
113+
{
114+
if (!(componentViewModel.Declaration is ModuleDeclaration moduleDeclaration))
115+
{
116+
return null;
117+
}
118+
119+
var targets = new List<ModuleDeclaration>{moduleDeclaration};
120+
var targetFolder = moduleDeclaration.CustomFolder;
121+
return new MoveMultipleToFolderModel(targets, targetFolder);
122+
}
123+
124+
private static void ExecuteRefactoringAction<TModel>(TModel model, IRefactoringAction<TModel> refactoringAction, IRefactoringFailureNotifier failureNotifier)
125+
where TModel : class, IRefactoringModel
126+
{
127+
try
128+
{
129+
refactoringAction.Refactor(model);
130+
}
131+
catch (RefactoringAbortedException)
132+
{}
133+
catch (RefactoringException exception)
134+
{
135+
failureNotifier.Notify(exception);
136+
}
137+
}
138+
}
139+
}

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

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,7 @@ public MoveContainingFolderRefactoringFailedNotifier(IMessageBox messageBox)
1111
: base(messageBox)
1212
{}
1313

14-
protected override string Caption => Resources.RubberduckUI.MoveToFolderDialog_Caption;
14+
protected override string Caption => Resources.RubberduckUI.MoveFoldersDialog_Caption;
1515

1616
protected override string Message(RefactoringException exception)
1717
{

Rubberduck.Resources/CodeExplorer/CodeExplorerUI.Designer.cs

Lines changed: 11 additions & 2 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

Rubberduck.Resources/CodeExplorer/CodeExplorerUI.cs.resx

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -259,7 +259,7 @@
259259
<value>Form (.frm)</value>
260260
</data>
261261
<data name="CodeExplorer_Rename" xml:space="preserve">
262-
<value>Přejmenovat</value>
262+
<value>Přejmenovat...</value>
263263
</data>
264264
<data name="CodeExplorer_SetAsStartupProject" xml:space="preserve">
265265
<value>Startovací projekt</value>
@@ -317,7 +317,7 @@ Pokračovat?</value>
317317
<value>Rubberduck: Uživatelské Deklarace - {0}</value>
318318
</data>
319319
<data name="CodeExplorer_ExtractInterfaceText" xml:space="preserve">
320-
<value>Extrahovat Interface</value>
320+
<value>Extrahovat Interface...</value>
321321
</data>
322322
<data name="SyncProject" xml:space="preserve">
323323
<value>Synchronizovat Projekt</value>

Rubberduck.Resources/CodeExplorer/CodeExplorerUI.de.resx

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -250,7 +250,7 @@
250250
<value>Formular (.frm)</value>
251251
</data>
252252
<data name="CodeExplorer_Rename" xml:space="preserve">
253-
<value>Umbenennen</value>
253+
<value>Umbenennen...</value>
254254
</data>
255255
<data name="CodeExplorer_SetAsStartupProject" xml:space="preserve">
256256
<value>Als Startprojekt festlegen</value>
@@ -320,9 +320,12 @@ Fortfahren?</value>
320320
<value>Projektinhalt durch Dateiinhalt ersetzen... </value>
321321
</data>
322322
<data name="CodeExplorer_ExtractInterfaceText" xml:space="preserve">
323-
<value>Interface extrahieren</value>
323+
<value>Interface extrahieren...</value>
324324
</data>
325325
<data name="CodeExplorer_AppendHeader" xml:space="preserve">
326326
<value>Rubberduck: Benutzerdefinierte Deklarationen - {0}</value>
327327
</data>
328+
<data name="CodeExplorer_MoveToFolder" xml:space="preserve">
329+
<value>In Ordner verschieben...</value>
330+
</data>
328331
</root>

Rubberduck.Resources/CodeExplorer/CodeExplorerUI.es.resx

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -256,7 +256,7 @@
256256
<value>Form (.frm)</value>
257257
</data>
258258
<data name="CodeExplorer_Rename" xml:space="preserve">
259-
<value>Rebautizar</value>
259+
<value>Rebautizar...</value>
260260
</data>
261261
<data name="CodeExplorer_SetAsStartupProject" xml:space="preserve">
262262
<value>Establecer como inicio</value>

Rubberduck.Resources/CodeExplorer/CodeExplorerUI.fr.resx

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -256,7 +256,7 @@
256256
<value>Formulaire (.frm)</value>
257257
</data>
258258
<data name="CodeExplorer_Rename" xml:space="preserve">
259-
<value>Renommer</value>
259+
<value>Renommer...</value>
260260
</data>
261261
<data name="CodeExplorer_SetAsStartupProject" xml:space="preserve">
262262
<value>Lancer au démarrage</value>
@@ -317,7 +317,7 @@ Continuer?</value>
317317
<value>Remplacer le contenu des fichiers...</value>
318318
</data>
319319
<data name="CodeExplorer_ExtractInterfaceText" xml:space="preserve">
320-
<value>Extraire une interface</value>
320+
<value>Extraire une interface...</value>
321321
</data>
322322
<data name="UpdateFromFiles" xml:space="preserve">
323323
<value>Remplacer le contenu du projet...</value>

Rubberduck.Resources/CodeExplorer/CodeExplorerUI.resx

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -341,7 +341,7 @@
341341
<value>Form (.frm)</value>
342342
</data>
343343
<data name="CodeExplorer_Rename" xml:space="preserve">
344-
<value>Rename</value>
344+
<value>Rename...</value>
345345
</data>
346346
<data name="CodeExplorer_SetAsStartupProject" xml:space="preserve">
347347
<value>Set as start up</value>
@@ -444,7 +444,7 @@ Continue?</value>
444444
<value>Rubberduck User Declarations - {0}</value>
445445
</data>
446446
<data name="CodeExplorer_ExtractInterfaceText" xml:space="preserve">
447-
<value>Extract Interface</value>
447+
<value>Extract Interface...</value>
448448
</data>
449449
<data name="SyncProject" xml:space="preserve">
450450
<value>Sync Project</value>
@@ -455,4 +455,7 @@ Continue?</value>
455455
<data name="ReplaceFromFiles" xml:space="preserve">
456456
<value>Replace Contents from Files...</value>
457457
</data>
458+
<data name="CodeExplorer_MoveToFolder" xml:space="preserve">
459+
<value>Move to Folder...</value>
460+
</data>
458461
</root>

0 commit comments

Comments
 (0)