Skip to content

Commit 5d20c1a

Browse files
committed
Refactor ImportCommand
This is a preparation for the introduction of subtypes.
1 parent fc6cae1 commit 5d20c1a

File tree

2 files changed

+87
-47
lines changed

2 files changed

+87
-47
lines changed

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

Lines changed: 86 additions & 46 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,10 @@
11
using System;
22
using System.Collections.Generic;
3+
using System.IO;
34
using System.Linq;
45
using System.Windows.Forms;
56
using Rubberduck.Navigation.CodeExplorer;
7+
using Rubberduck.Parsing.VBA;
68
using Rubberduck.Resources;
79
using Rubberduck.VBEditor.Events;
810
using Rubberduck.VBEditor.SafeComWrappers;
@@ -24,15 +26,18 @@ public class ImportCommand : CodeExplorerCommandBase
2426
private readonly IFileSystemBrowserFactory _dialogFactory;
2527
private readonly IList<string> _importableExtensions;
2628
private readonly string _filterExtensions;
29+
private readonly IParseManager _parseManager;
2730

2831
public ImportCommand(
29-
IVBE vbe,
30-
IFileSystemBrowserFactory dialogFactory,
31-
IVbeEvents vbeEvents)
32+
IVBE vbe,
33+
IFileSystemBrowserFactory dialogFactory,
34+
IVbeEvents vbeEvents,
35+
IParseManager parseManager)
3236
: base(vbeEvents)
3337
{
3438
_vbe = vbe;
3539
_dialogFactory = dialogFactory;
40+
_parseManager = parseManager;
3641

3742
AddToCanExecuteEvaluation(SpecialEvaluateCanExecute);
3843

@@ -44,6 +49,7 @@ public ImportCommand(
4449
_filterExtensions = string.Join("; ", _importableExtensions.Select(ext => $"*.{ext}"));
4550

4651
AddToCanExecuteEvaluation(SpecialEvaluateCanExecute);
52+
AddToOnExecuteEvaluation(SpecialEvaluateCanExecute);
4753
}
4854

4955
public sealed override IEnumerable<Type> ApplicableNodeTypes => ApplicableNodes;
@@ -61,37 +67,42 @@ private bool ThereIsAValidActiveProject()
6167
}
6268
}
6369

64-
protected override void OnExecute(object parameter)
70+
private (IVBProject project, bool needsDisposal) TargetProject(object parameter)
6571
{
66-
if (!CanExecute(parameter))
72+
var targetProject = TargetProjectFromParameter(parameter);
73+
if (targetProject != null)
6774
{
68-
return;
75+
return (targetProject, false);
6976
}
7077

71-
var usingFreshProjectWrapper = false;
72-
var project = (parameter as CodeExplorerItemViewModel)?.Declaration?.Project;
78+
targetProject = TargetProjectFromVbe();
79+
80+
return (targetProject, targetProject != null);
81+
}
82+
83+
private static IVBProject TargetProjectFromParameter(object parameter)
84+
{
85+
return (parameter as CodeExplorerItemViewModel)?.Declaration?.Project;
86+
}
7387

74-
if (project == null)
88+
private IVBProject TargetProjectFromVbe()
89+
{
90+
if (_vbe.ProjectsCount == 1)
7591
{
76-
if (_vbe.ProjectsCount == 1)
77-
{
78-
usingFreshProjectWrapper = true;
79-
using (var projects = _vbe.VBProjects)
80-
{
81-
project = projects[1];
82-
}
83-
}
84-
else if (ThereIsAValidActiveProject())
92+
using (var projects = _vbe.VBProjects)
8593
{
86-
usingFreshProjectWrapper = true;
87-
project = _vbe.ActiveVBProject;
88-
}
89-
else
90-
{
91-
return;
94+
return projects[1];
9295
}
9396
}
9497

98+
var activeProject = _vbe.ActiveVBProject;
99+
return activeProject != null && !activeProject.IsWrappingNullReference
100+
? activeProject
101+
: null;
102+
}
103+
104+
protected virtual ICollection<string> FilesToImport(object parameter)
105+
{
95106
using (var dialog = _dialogFactory.CreateOpenFileDialog())
96107
{
97108
dialog.AddExtension = true;
@@ -100,42 +111,71 @@ protected override void OnExecute(object parameter)
100111
dialog.CheckPathExists = true;
101112
dialog.Multiselect = true;
102113
dialog.ShowHelp = false;
103-
dialog.Title = RubberduckUI.ImportCommand_OpenDialog_Title;
104-
dialog.Filter =
114+
dialog.Title = FileDialogTitle;
115+
dialog.Filter =
105116
$"{RubberduckUI.ImportCommand_OpenDialog_Filter_VBFiles} ({_filterExtensions})|{_filterExtensions}|" +
106117
$"{RubberduckUI.ImportCommand_OpenDialog_Filter_AllFiles}, (*.*)|*.*";
107118

108-
if (project == null || dialog.ShowDialog() != DialogResult.OK)
119+
if (dialog.ShowDialog() != DialogResult.OK)
109120
{
110-
if (usingFreshProjectWrapper)
111-
{
112-
project?.Dispose();
113-
}
114-
return;
121+
return new List<string>();
115122
}
116123

117-
var fileExists = dialog.FileNames.Select(s => s.Split('.').Last());
118-
if (fileExists.Any(fileExt => !_importableExtensions.Contains(fileExt)))
124+
var fileNames = dialog.FileNames;
125+
var fileExtensions = fileNames.Select(Path.GetExtension);
126+
if (fileExtensions.Any(fileExt => !_importableExtensions.Contains(fileExt)))
119127
{
120-
if (usingFreshProjectWrapper)
121-
{
122-
project.Dispose();
123-
}
124-
return;
128+
return new List<string>();
125129
}
126130

127-
foreach (var filename in dialog.FileNames)
131+
return fileNames;
132+
}
133+
}
134+
135+
protected virtual string FileDialogTitle => RubberduckUI.ImportCommand_OpenDialog_Title;
136+
137+
private void ImportFilesWithSuspension(IEnumerable<string> filesToImport, IVBProject targetProject)
138+
{
139+
var suspensionResult = _parseManager.OnSuspendParser(this, new[] {ParserState.Ready}, () => ImportFiles(filesToImport, targetProject));
140+
if (suspensionResult != SuspensionResult.Completed)
141+
{
142+
Logger.Warn("File import failed due to suspension failure.");
143+
}
144+
}
145+
146+
protected virtual void ImportFiles(ICollection<string> filesToImport, IVBProject targetProject)
147+
{
148+
using (var components = targetProject.VBComponents)
149+
{
150+
foreach (var filename in filesToImport)
128151
{
129-
using (var components = project.VBComponents)
130-
{
131-
components.Import(filename);
132-
}
152+
//We have to dispose the return value.
153+
using (components.Import(filename)) {}
133154
}
134155
}
156+
}
157+
158+
protected override void OnExecute(object parameter)
159+
{
160+
var (targetProject, targetProjectNeedsDisposal) = TargetProject(parameter);
161+
162+
if (targetProject == null)
163+
{
164+
return;
165+
}
166+
167+
var filesToImport = FilesToImport(parameter);
168+
169+
if (!filesToImport.Any())
170+
{
171+
return;
172+
}
173+
174+
ImportFilesWithSuspension(filesToImport, targetProject);
135175

136-
if (usingFreshProjectWrapper)
176+
if (targetProjectNeedsDisposal)
137177
{
138-
project.Dispose();
178+
targetProject.Dispose();
139179
}
140180
}
141181
}

RubberduckTests/CodeExplorer/MockedCodeExplorer.cs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -339,7 +339,7 @@ public void ExecuteAddTestModuleWithStubsCommand()
339339

340340
public void ExecuteImportCommand()
341341
{
342-
ViewModel.ImportCommand = new ImportCommand(Vbe.Object, BrowserFactory.Object, VbeEvents.Object);
342+
ViewModel.ImportCommand = new ImportCommand(Vbe.Object, BrowserFactory.Object, VbeEvents.Object, State);
343343
ViewModel.ImportCommand.Execute(ViewModel.SelectedItem);
344344
}
345345

0 commit comments

Comments
 (0)