Skip to content

Commit c289e18

Browse files
committed
Notify user about bad input to import commands
1 parent af68499 commit c289e18

File tree

7 files changed

+270
-28
lines changed

7 files changed

+270
-28
lines changed

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

Lines changed: 18 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@
33
using System.IO;
44
using System.Linq;
55
using System.Windows.Forms;
6+
using Rubberduck.Interaction;
67
using Rubberduck.Navigation.CodeExplorer;
78
using Rubberduck.Parsing.VBA;
89
using Rubberduck.Resources;
@@ -29,17 +30,22 @@ public class ImportCommand : CodeExplorerCommandBase
2930
private readonly string _filterExtensions;
3031
private readonly IParseManager _parseManager;
3132

33+
protected readonly IMessageBox MessageBox;
34+
3235
public ImportCommand(
3336
IVBE vbe,
3437
IFileSystemBrowserFactory dialogFactory,
3538
IVbeEvents vbeEvents,
36-
IParseManager parseManager)
39+
IParseManager parseManager,
40+
IMessageBox messageBox)
3741
: base(vbeEvents)
3842
{
3943
_vbe = vbe;
4044
_dialogFactory = dialogFactory;
4145
_parseManager = parseManager;
4246

47+
MessageBox = messageBox;
48+
4349
AddToCanExecuteEvaluation(SpecialEvaluateCanExecute);
4450

4551
ComponentTypeForExtension = ComponentTypeExtensions.ComponentTypeForExtension(_vbe.Kind);
@@ -110,7 +116,7 @@ protected virtual ICollection<string> FilesToImport(object parameter)
110116
dialog.CheckPathExists = true;
111117
dialog.Multiselect = true;
112118
dialog.ShowHelp = false;
113-
dialog.Title = FileDialogTitle;
119+
dialog.Title = DialogsTitle;
114120
dialog.Filter =
115121
$"{RubberduckUI.ImportCommand_OpenDialog_Filter_VBFiles} ({_filterExtensions})|{_filterExtensions}|" +
116122
$"{RubberduckUI.ImportCommand_OpenDialog_Filter_AllFiles}, (*.*)|*.*";
@@ -124,15 +130,23 @@ protected virtual ICollection<string> FilesToImport(object parameter)
124130
var fileExtensions = fileNames.Select(Path.GetExtension);
125131
if (fileExtensions.Any(fileExt => !_importableExtensions.Contains(fileExt)))
126132
{
127-
//TODO: report this to the user.
133+
NotifyUserAboutAbortDueToUnsupportedFileExtensions(fileNames);
128134
return new List<string>();
129135
}
130136

131137
return fileNames;
132138
}
133139
}
134140

135-
protected virtual string FileDialogTitle => RubberduckUI.ImportCommand_OpenDialog_Title;
141+
protected virtual string DialogsTitle => RubberduckUI.ImportCommand_OpenDialog_Title;
142+
143+
private void NotifyUserAboutAbortDueToUnsupportedFileExtensions(IEnumerable<string> fileNames)
144+
{
145+
var firstUnsupportedFile = fileNames.First(filename => !_importableExtensions.Contains(Path.GetExtension(filename)));
146+
var unsupportedFileName = Path.GetFileName(firstUnsupportedFile);
147+
var message = string.Format(RubberduckUI.ImportCommand_UnsupportedFileExtensions, unsupportedFileName);
148+
MessageBox.NotifyWarn(message, DialogsTitle);
149+
}
136150

137151
private void ImportFilesWithSuspension(ICollection<string> filesToImport, IVBProject targetProject)
138152
{

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

Lines changed: 19 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,8 @@
11
using System.Collections.Generic;
22
using System.Linq;
3+
using Rubberduck.Interaction;
34
using Rubberduck.Parsing.VBA;
5+
using Rubberduck.Resources;
46
using Rubberduck.VBEditor.Events;
57
using Rubberduck.VBEditor.SafeComWrappers;
68
using Rubberduck.VBEditor.SafeComWrappers.Abstract;
@@ -13,18 +15,31 @@ public ReplaceProjectContentsFromFilesCommand(
1315
IVBE vbe,
1416
IFileSystemBrowserFactory dialogFactory,
1517
IVbeEvents vbeEvents,
16-
IParseManager parseManager)
17-
:base(vbe, dialogFactory, vbeEvents, parseManager)
18-
{}
18+
IParseManager parseManager,
19+
IMessageBox messageBox)
20+
:base(vbe, dialogFactory, vbeEvents, parseManager, messageBox)
21+
{ }
22+
23+
protected override string DialogsTitle => RubberduckUI.ReplaceProjectContentsFromFilesCommand_DialogCaption;
1924

2025
protected override void ImportFiles(ICollection<string> filesToImport, IVBProject targetProject)
2126
{
22-
//TODO: Ask for confirmation to delete the project contents and replace them with the selected modules.
27+
if (!UserConfirmsToReplaceProjectContents(targetProject))
28+
{
29+
return;
30+
}
2331

2432
RemoveReimportableComponents(targetProject);
2533
base.ImportFiles(filesToImport, targetProject);
2634
}
2735

36+
private bool UserConfirmsToReplaceProjectContents(IVBProject project)
37+
{
38+
var projectName = project.Name;
39+
var message = string.Format(RubberduckUI.ReplaceProjectContentsFromFilesCommand_DialogCaption, projectName);
40+
return MessageBox.ConfirmYesNo(message, DialogsTitle, false);
41+
}
42+
2843
private void RemoveReimportableComponents(IVBProject project)
2944
{
3045
var reimportableComponentTypes = ComponentTypeForExtension.Values

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

Lines changed: 61 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,11 @@
11
using System.Collections.Generic;
22
using System.IO;
33
using System.Linq;
4+
using Rubberduck.Interaction;
45
using Rubberduck.Parsing.VBA;
56
using Rubberduck.Parsing.VBA.DeclarationCaching;
67
using Rubberduck.Parsing.VBA.Extensions;
8+
using Rubberduck.Resources;
79
using Rubberduck.VBEditor;
810
using Rubberduck.VBEditor.Events;
911
using Rubberduck.VBEditor.ComManagement;
@@ -27,14 +29,17 @@ public UpdateFromFilesCommand(
2729
IParseManager parseManager,
2830
IDeclarationFinderProvider declarationFinderProvider,
2931
IProjectsProvider projectsProvider,
30-
IModuleNameFromFileExtractor moduleNameFromFileExtractor)
31-
: base(vbe, dialogFactory, vbeEvents, parseManager)
32+
IModuleNameFromFileExtractor moduleNameFromFileExtractor,
33+
IMessageBox messageBox)
34+
: base(vbe, dialogFactory, vbeEvents, parseManager, messageBox)
3235
{
3336
_projectsProvider = projectsProvider;
3437
_declarationFinderProvider = declarationFinderProvider;
3538
_moduleNameFromFileExtractor = moduleNameFromFileExtractor;
3639
}
3740

41+
protected override string DialogsTitle => RubberduckUI.UpdateFromFilesCommand_DialogCaption;
42+
3843
protected override void ImportFiles(ICollection<string> filesToImport, IVBProject targetProject)
3944
{
4045
var finder = _declarationFinderProvider.DeclarationFinder;
@@ -56,15 +61,15 @@ protected override void ImportFiles(ICollection<string> filesToImport, IVBProjec
5661

5762
if (!ValuesAreUnique(moduleNames))
5863
{
59-
//TODO: report this to the user.
64+
NotifyUserAboutAbortDueToDuplicateComponent(moduleNames);
6065
return;
6166
}
6267

63-
var modules = Modules(moduleNames, targetProject.ProjectId, finder);
68+
var modulesToRemoveBeforeImport = Modules(moduleNames, targetProject.ProjectId, finder);
6469

65-
if(!modules.All(kvp => HasMatchingFileExtension(kvp.Key, kvp.Value)))
70+
if(!modulesToRemoveBeforeImport.All(kvp => HasMatchingFileExtension(kvp.Key, kvp.Value)))
6671
{
67-
//TODO: report this to the user.
72+
NotifyUserAboutAbortDueToNonMatchingFileExtension(modulesToRemoveBeforeImport);
6873
return;
6974
}
7075

@@ -75,37 +80,37 @@ protected override void ImportFiles(ICollection<string> filesToImport, IVBProjec
7580
&& componentType == ComponentType.Document)
7681
.ToHashSet();
7782

78-
//We can only insert inte existing documents.
79-
if (!documentFiles.All(filename => modules.ContainsKey(filename)))
83+
//We can only insert into existing documents.
84+
if (!documentFiles.All(filename => modulesToRemoveBeforeImport.ContainsKey(filename)))
8085
{
81-
//TODO: report this to the user.
86+
NotifyUserAboutAbortDueToNonExistingDocument(documentFiles, moduleNames, modulesToRemoveBeforeImport);
8287
return;
8388
}
8489

8590
//We must not remove document modules.
8691
foreach (var filename in documentFiles)
8792
{
88-
modules.Remove(filename);
93+
modulesToRemoveBeforeImport.Remove(filename);
8994
}
9095

9196
//We import the standalone code behind by replacing the code in an existing form.
9297
//So, the form has to exist already.
93-
if (!formFilesWithoutBinaries.All(filename => modules.ContainsKey(filename)))
98+
if (!formFilesWithoutBinaries.All(filename => modulesToRemoveBeforeImport.ContainsKey(filename)))
9499
{
95-
//TODO: report this to the user.
100+
NotifyUserAboutAbortDueToNonExistingUserForm(documentFiles, moduleNames, modulesToRemoveBeforeImport);
96101
return;
97102
}
98103

99104
foreach (var filename in formFilesWithoutBinaries)
100105
{
101-
modules.Remove(filename);
106+
modulesToRemoveBeforeImport.Remove(filename);
102107
}
103108

104109
using (var components = targetProject.VBComponents)
105110
{
106111
foreach (var filename in filesToImport)
107112
{
108-
if (modules.TryGetValue(filename, out var module))
113+
if (modulesToRemoveBeforeImport.TryGetValue(filename, out var module))
109114
{
110115
var component = _projectsProvider.Component(module);
111116
components.Remove(component);
@@ -172,6 +177,16 @@ private bool ValuesAreUnique(Dictionary<string, string> moduleNames)
172177
.All(moduleNameGroup => moduleNameGroup.Count() == 1);
173178
}
174179

180+
private void NotifyUserAboutAbortDueToDuplicateComponent(IDictionary<string, string> moduleNames)
181+
{
182+
var firstDuplicateModuleName = moduleNames
183+
.GroupBy(kvp => kvp.Value)
184+
.First(moduleNameGroup => moduleNameGroup.Count() > 1)
185+
.Key;
186+
var message = string.Format(RubberduckUI.UpdateFromFilesCommand_DuplicateModule, firstDuplicateModuleName);
187+
MessageBox.NotifyWarn(message, DialogsTitle);
188+
}
189+
175190
private ICollection<string> FormFilesWithoutBinaries(IDictionary<string, string> moduleNames, ICollection<string> formBinaryModuleNames)
176191
{
177192
return moduleNames
@@ -204,5 +219,37 @@ private bool HasMatchingFileExtension(string filename, QualifiedModuleName modul
204219
&& ComponentTypeForExtension.TryGetValue(fileExtension, out var componentType)
205220
&& module.ComponentType.Equals(componentType);
206221
}
222+
223+
private void NotifyUserAboutAbortDueToNonMatchingFileExtension(IDictionary<string, QualifiedModuleName> modules)
224+
{
225+
var (firstNonMatchingFileName, firstNonMatchingModule) = modules.First(kvp => !HasMatchingFileExtension(kvp.Key, kvp.Value));
226+
var message = string.Format(
227+
RubberduckUI.UpdateFromFilesCommand_DifferentComponentType,
228+
firstNonMatchingModule.ComponentName,
229+
firstNonMatchingFileName);
230+
MessageBox.NotifyWarn(message, DialogsTitle);
231+
}
232+
233+
private void NotifyUserAboutAbortDueToNonExistingDocument(ICollection<string> documentFiles, IDictionary<string, string> moduleNames, IDictionary<string, QualifiedModuleName> existingModules)
234+
{
235+
var firstNonExistingDocumentFilename = documentFiles.First(filename => !existingModules.ContainsKey(filename));
236+
var firstNonExistingDocumentModuleName = moduleNames[firstNonExistingDocumentFilename];
237+
var message = string.Format(
238+
RubberduckUI.UpdateFromFilesCommand_DocumentDoesNotExist,
239+
firstNonExistingDocumentModuleName,
240+
firstNonExistingDocumentFilename);
241+
MessageBox.NotifyWarn(message, DialogsTitle);
242+
}
243+
244+
private void NotifyUserAboutAbortDueToNonExistingUserForm(ICollection<string> userFormFiles, IDictionary<string, string> moduleNames, IDictionary<string, QualifiedModuleName> existingModules)
245+
{
246+
var firstNonExistingUserFormFilename = userFormFiles.First(filename => !existingModules.ContainsKey(filename));
247+
var firstNonExistingUserFormModuleName = moduleNames[firstNonExistingUserFormFilename];
248+
var message = string.Format(
249+
RubberduckUI.UpdateFromFilesCommand_UserFormDoesNotExist,
250+
firstNonExistingUserFormModuleName,
251+
firstNonExistingUserFormFilename);
252+
MessageBox.NotifyWarn(message, DialogsTitle);
253+
}
207254
}
208255
}

Rubberduck.Resources/RubberduckUI.Designer.cs

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

0 commit comments

Comments
 (0)