1
1
using System ;
2
2
using System . Collections . Generic ;
3
+ using System . IO ;
3
4
using System . Linq ;
4
5
using System . Windows . Forms ;
6
+ using Rubberduck . Interaction ;
5
7
using Rubberduck . Navigation . CodeExplorer ;
8
+ using Rubberduck . Parsing . VBA ;
6
9
using Rubberduck . Resources ;
7
10
using Rubberduck . VBEditor . Events ;
11
+ using Rubberduck . VBEditor . Extensions ;
8
12
using Rubberduck . VBEditor . SafeComWrappers ;
9
13
using Rubberduck . VBEditor . SafeComWrappers . Abstract ;
10
14
@@ -24,26 +28,33 @@ public class ImportCommand : CodeExplorerCommandBase
24
28
private readonly IFileSystemBrowserFactory _dialogFactory ;
25
29
private readonly IList < string > _importableExtensions ;
26
30
private readonly string _filterExtensions ;
31
+ private readonly IParseManager _parseManager ;
32
+
33
+ protected readonly IMessageBox MessageBox ;
27
34
28
35
public ImportCommand (
29
- IVBE vbe ,
30
- IFileSystemBrowserFactory dialogFactory ,
31
- IVbeEvents vbeEvents )
36
+ IVBE vbe ,
37
+ IFileSystemBrowserFactory dialogFactory ,
38
+ IVbeEvents vbeEvents ,
39
+ IParseManager parseManager ,
40
+ IMessageBox messageBox )
32
41
: base ( vbeEvents )
33
42
{
34
43
_vbe = vbe ;
35
44
_dialogFactory = dialogFactory ;
45
+ _parseManager = parseManager ;
46
+
47
+ MessageBox = messageBox ;
36
48
37
49
AddToCanExecuteEvaluation ( SpecialEvaluateCanExecute ) ;
38
50
39
- _importableExtensions =
40
- vbe . Kind == VBEKind . Hosted
41
- ? new List < string > { "bas" , "cls" , "frm" , "doccls" } // VBA
42
- : new List < string > { "bas" , "cls" , "frm" , "ctl" , "pag" , "dob" } ; // VB6
51
+ ComponentTypeForExtension = ComponentTypeExtensions . ComponentTypeForExtension ( _vbe . Kind ) ;
43
52
44
- _filterExtensions = string . Join ( "; " , _importableExtensions . Select ( ext => $ "*.{ ext } ") ) ;
53
+ _importableExtensions = ComponentTypeForExtension . Keys . ToList ( ) ;
54
+ _filterExtensions = string . Join ( "; " , _importableExtensions . Select ( ext => $ "*{ ext } ") ) ;
45
55
46
56
AddToCanExecuteEvaluation ( SpecialEvaluateCanExecute ) ;
57
+ AddToOnExecuteEvaluation ( SpecialEvaluateCanExecute ) ;
47
58
}
48
59
49
60
public sealed override IEnumerable < Type > ApplicableNodeTypes => ApplicableNodes ;
@@ -61,37 +72,42 @@ private bool ThereIsAValidActiveProject()
61
72
}
62
73
}
63
74
64
- protected override void OnExecute ( object parameter )
75
+ private ( IVBProject project , bool needsDisposal ) TargetProject ( object parameter )
65
76
{
66
- if ( ! CanExecute ( parameter ) )
77
+ var targetProject = TargetProjectFromParameter ( parameter ) ;
78
+ if ( targetProject != null )
67
79
{
68
- return ;
80
+ return ( targetProject , false ) ;
69
81
}
70
82
71
- var usingFreshProjectWrapper = false ;
72
- var project = ( parameter as CodeExplorerItemViewModel ) ? . Declaration ? . Project ;
83
+ targetProject = TargetProjectFromVbe ( ) ;
84
+
85
+ return ( targetProject , targetProject != null ) ;
86
+ }
87
+
88
+ private static IVBProject TargetProjectFromParameter ( object parameter )
89
+ {
90
+ return ( parameter as CodeExplorerItemViewModel ) ? . Declaration ? . Project ;
91
+ }
73
92
74
- if ( project == null )
93
+ private IVBProject TargetProjectFromVbe ( )
94
+ {
95
+ if ( _vbe . ProjectsCount == 1 )
75
96
{
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 ( ) )
97
+ using ( var projects = _vbe . VBProjects )
85
98
{
86
- usingFreshProjectWrapper = true ;
87
- project = _vbe . ActiveVBProject ;
88
- }
89
- else
90
- {
91
- return ;
99
+ return projects [ 1 ] ;
92
100
}
93
101
}
94
102
103
+ var activeProject = _vbe . ActiveVBProject ;
104
+ return activeProject != null && ! activeProject . IsWrappingNullReference
105
+ ? activeProject
106
+ : null ;
107
+ }
108
+
109
+ protected virtual ICollection < string > FilesToImport ( object parameter )
110
+ {
95
111
using ( var dialog = _dialogFactory . CreateOpenFileDialog ( ) )
96
112
{
97
113
dialog . AddExtension = true ;
@@ -100,43 +116,94 @@ protected override void OnExecute(object parameter)
100
116
dialog . CheckPathExists = true ;
101
117
dialog . Multiselect = true ;
102
118
dialog . ShowHelp = false ;
103
- dialog . Title = RubberduckUI . ImportCommand_OpenDialog_Title ;
104
- dialog . Filter =
119
+ dialog . Title = DialogsTitle ;
120
+ dialog . Filter =
105
121
$ "{ RubberduckUI . ImportCommand_OpenDialog_Filter_VBFiles } ({ _filterExtensions } )|{ _filterExtensions } |" +
106
122
$ "{ RubberduckUI . ImportCommand_OpenDialog_Filter_AllFiles } , (*.*)|*.*";
107
123
108
- if ( project == null || dialog . ShowDialog ( ) != DialogResult . OK )
124
+ if ( dialog . ShowDialog ( ) != DialogResult . OK )
109
125
{
110
- if ( usingFreshProjectWrapper )
111
- {
112
- project ? . Dispose ( ) ;
113
- }
114
- return ;
126
+ return new List < string > ( ) ;
115
127
}
116
128
117
- var fileExists = dialog . FileNames . Select ( s => s . Split ( '.' ) . Last ( ) ) ;
118
- if ( fileExists . Any ( fileExt => ! _importableExtensions . Contains ( fileExt ) ) )
129
+ var fileNames = dialog . FileNames ;
130
+ var fileExtensions = fileNames . Select ( Path . GetExtension ) ;
131
+ if ( fileExtensions . Any ( fileExt => ! _importableExtensions . Contains ( fileExt ) ) )
119
132
{
120
- if ( usingFreshProjectWrapper )
121
- {
122
- project . Dispose ( ) ;
123
- }
124
- return ;
133
+ NotifyUserAboutAbortDueToUnsupportedFileExtensions ( fileNames ) ;
134
+ return new List < string > ( ) ;
125
135
}
126
136
127
- foreach ( var filename in dialog . FileNames )
137
+ return fileNames ;
138
+ }
139
+ }
140
+
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
+ }
150
+
151
+ private void ImportFilesWithSuspension ( ICollection < string > filesToImport , IVBProject targetProject )
152
+ {
153
+ var suspensionResult = _parseManager . OnSuspendParser ( this , new [ ] { ParserState . Ready } , ( ) => ImportFiles ( filesToImport , targetProject ) ) ;
154
+ if ( suspensionResult != SuspensionResult . Completed )
155
+ {
156
+ Logger . Warn ( "File import failed due to suspension failure." ) ;
157
+ }
158
+ }
159
+
160
+ protected virtual void ImportFiles ( ICollection < string > filesToImport , IVBProject targetProject )
161
+ {
162
+ using ( var components = targetProject . VBComponents )
163
+ {
164
+ foreach ( var filename in filesToImport )
128
165
{
129
- using ( var components = project . VBComponents )
166
+ var fileExtension = Path . GetExtension ( filename ) ;
167
+ if ( fileExtension != null
168
+ && ComponentTypeForExtension . TryGetValue ( fileExtension , out var componentType )
169
+ && componentType == ComponentType . Document )
130
170
{
131
- components . Import ( filename ) ;
171
+ //We have to dispose the return value.
172
+ using ( components . ImportSourceFile ( filename ) ) { }
173
+ }
174
+ else
175
+ {
176
+ //We have to dispose the return value.
177
+ using ( components . Import ( filename ) ) { }
132
178
}
133
179
}
134
180
}
181
+ }
135
182
136
- if ( usingFreshProjectWrapper )
183
+ protected override void OnExecute ( object parameter )
184
+ {
185
+ var ( targetProject , targetProjectNeedsDisposal ) = TargetProject ( parameter ) ;
186
+
187
+ if ( targetProject == null )
137
188
{
138
- project . Dispose ( ) ;
189
+ return ;
190
+ }
191
+
192
+ var filesToImport = FilesToImport ( parameter ) ;
193
+
194
+ if ( ! filesToImport . Any ( ) )
195
+ {
196
+ return ;
197
+ }
198
+
199
+ ImportFilesWithSuspension ( filesToImport , targetProject ) ;
200
+
201
+ if ( targetProjectNeedsDisposal )
202
+ {
203
+ targetProject . Dispose ( ) ;
139
204
}
140
205
}
206
+
207
+ protected IDictionary < string , ComponentType > ComponentTypeForExtension { get ; }
141
208
}
142
209
}
0 commit comments