3
3
using System . Collections . ObjectModel ;
4
4
using System . Drawing ;
5
5
using System . Globalization ;
6
+ using System . IO ;
6
7
using System . Linq ;
7
8
using System . Windows . Forms ;
8
9
using System . Windows . Input ;
9
10
using System . Windows . Media . Imaging ;
10
11
using Microsoft . Vbe . Interop ;
11
12
using Ninject ;
13
+ using NLog ;
12
14
using Rubberduck . Parsing . VBA ;
13
15
using Rubberduck . SourceControl ;
14
16
using Rubberduck . UI . Command ;
@@ -35,6 +37,9 @@ public sealed class SourceControlViewViewModel : ViewModelBase, IDisposable
35
37
private readonly ISourceControlConfigProvider _configService ;
36
38
private readonly SourceControlSettings _config ;
37
39
private readonly ICodePaneWrapperFactory _wrapperFactory ;
40
+ private readonly IMessageBox _messageBox ;
41
+ private readonly FileSystemWatcher _fileSystemWatcher ;
42
+ private static readonly Logger Logger = LogManager . GetCurrentClassLogger ( ) ;
38
43
39
44
public SourceControlViewViewModel (
40
45
VBE vbe ,
@@ -46,7 +51,8 @@ public SourceControlViewViewModel(
46
51
[ Named ( "branchesView" ) ] IControlView branchesView ,
47
52
[ Named ( "unsyncedCommitsView" ) ] IControlView unsyncedCommitsView ,
48
53
[ Named ( "settingsView" ) ] IControlView settingsView ,
49
- ICodePaneWrapperFactory wrapperFactory )
54
+ ICodePaneWrapperFactory wrapperFactory ,
55
+ IMessageBox messageBox )
50
56
{
51
57
_vbe = vbe ;
52
58
_state = state ;
@@ -58,6 +64,7 @@ public SourceControlViewViewModel(
58
64
_configService = configService ;
59
65
_config = _configService . Create ( ) ;
60
66
_wrapperFactory = wrapperFactory ;
67
+ _messageBox = messageBox ;
61
68
62
69
_initRepoCommand = new DelegateCommand ( _ => InitRepo ( ) ) ;
63
70
_openRepoCommand = new DelegateCommand ( _ => OpenRepo ( ) ) ;
@@ -87,6 +94,8 @@ public SourceControlViewViewModel(
87
94
Status = RubberduckUI . Offline ;
88
95
89
96
ListenForErrors ( ) ;
97
+
98
+ _fileSystemWatcher = new FileSystemWatcher ( ) ;
90
99
}
91
100
92
101
public void SetTab ( SourceControlTab tab )
@@ -98,22 +107,47 @@ public void AddComponent(VBComponent component)
98
107
{
99
108
if ( Provider == null ) { return ; }
100
109
110
+ _fileSystemWatcher . EnableRaisingEvents = false ;
101
111
var fileStatus = Provider . Status ( ) . SingleOrDefault ( stat => stat . FilePath . Split ( '.' ) [ 0 ] == component . Name ) ;
102
112
if ( fileStatus != null )
103
113
{
104
114
Provider . AddFile ( fileStatus . FilePath ) ;
105
115
}
116
+ _fileSystemWatcher . EnableRaisingEvents = true ;
106
117
}
107
118
108
119
public void RemoveComponent ( VBComponent component )
109
120
{
110
121
if ( Provider == null ) { return ; }
111
122
123
+ _fileSystemWatcher . EnableRaisingEvents = false ;
112
124
var fileStatus = Provider . Status ( ) . SingleOrDefault ( stat => stat . FilePath . Split ( '.' ) [ 0 ] == component . Name ) ;
113
125
if ( fileStatus != null )
114
126
{
115
127
Provider . RemoveFile ( fileStatus . FilePath , true ) ;
116
128
}
129
+ _fileSystemWatcher . EnableRaisingEvents = true ;
130
+ }
131
+
132
+ public void RenameComponent ( VBComponent component , string oldName )
133
+ {
134
+ if ( Provider == null ) { return ; }
135
+
136
+ var fileStatus = Provider . LastKnownStatus ( ) . SingleOrDefault ( stat => stat . FilePath . Split ( '.' ) [ 0 ] == oldName ) ;
137
+ if ( fileStatus != null )
138
+ {
139
+ _fileSystemWatcher . EnableRaisingEvents = false ;
140
+ var directory = Provider . CurrentRepository . LocalLocation ;
141
+ directory += directory . EndsWith ( "\\ " ) ? string . Empty : "\\ " ;
142
+
143
+ var fileExt = "." + fileStatus . FilePath . Split ( '.' ) . Last ( ) ;
144
+
145
+ File . Move ( directory + fileStatus . FilePath , directory + component . Name + fileExt ) ;
146
+ Provider . RemoveFile ( oldName + fileExt , false ) ;
147
+ Provider . AddFile ( component . Name + fileExt ) ;
148
+
149
+ _fileSystemWatcher . EnableRaisingEvents = true ;
150
+ }
117
151
}
118
152
119
153
private static readonly IDictionary < NotificationType , BitmapImage > IconMappings =
@@ -125,7 +159,7 @@ public void RemoveComponent(VBComponent component)
125
159
126
160
private void _state_StateChanged ( object sender , ParserStateEventArgs e )
127
161
{
128
- if ( e . State == ParserState . Parsed )
162
+ if ( e . State == ParserState . Pending )
129
163
{
130
164
UiDispatcher . InvokeAsync ( Refresh ) ;
131
165
}
@@ -139,6 +173,86 @@ public ISourceControlProvider Provider
139
173
{
140
174
_provider = value ;
141
175
SetChildPresenterSourceControlProviders ( _provider ) ;
176
+
177
+ if ( _fileSystemWatcher . Path != LocalDirectory )
178
+ {
179
+ _fileSystemWatcher . Path = _provider . CurrentRepository . LocalLocation ;
180
+ _fileSystemWatcher . EnableRaisingEvents = true ;
181
+ _fileSystemWatcher . IncludeSubdirectories = true ;
182
+
183
+ _fileSystemWatcher . Created += _fileSystemWatcher_Created ;
184
+ _fileSystemWatcher . Deleted += _fileSystemWatcher_Deleted ;
185
+ _fileSystemWatcher . Renamed += _fileSystemWatcher_Renamed ;
186
+ _fileSystemWatcher . Changed += _fileSystemWatcher_Changed ;
187
+ }
188
+ }
189
+ }
190
+
191
+ private void _fileSystemWatcher_Changed ( object sender , FileSystemEventArgs e )
192
+ {
193
+ // the file system filter doesn't support multiple filters
194
+ if ( ! new [ ] { "cls" , "bas" , "frm" } . Contains ( e . Name . Split ( '.' ) . Last ( ) ) )
195
+ {
196
+ return ;
197
+ }
198
+
199
+ Logger . Trace ( "File system watcher detected file changed" ) ;
200
+ if ( _messageBox . Show ( "file changed" , RubberduckUI . SourceControlPanel_Caption ,
201
+ MessageBoxButtons . OKCancel , MessageBoxIcon . Information , MessageBoxDefaultButton . Button1 ) == DialogResult . OK )
202
+ {
203
+ UiDispatcher . InvokeAsync ( Refresh ) ;
204
+ }
205
+ }
206
+
207
+ private void _fileSystemWatcher_Renamed ( object sender , RenamedEventArgs e )
208
+ {
209
+ // the file system filter doesn't support multiple filters
210
+ if ( ! new [ ] { "cls" , "bas" , "frm" } . Contains ( e . Name . Split ( '.' ) . Last ( ) ) )
211
+ {
212
+ return ;
213
+ }
214
+
215
+ Logger . Trace ( "File system watcher detected file renamed" ) ;
216
+ if ( _messageBox . Show ( "file changed" , RubberduckUI . SourceControlPanel_Caption ,
217
+ MessageBoxButtons . OKCancel , MessageBoxIcon . Information , MessageBoxDefaultButton . Button1 ) == DialogResult . OK )
218
+ {
219
+ Provider . RemoveFile ( e . OldFullPath , true ) ;
220
+ Provider . AddFile ( e . FullPath ) ;
221
+ UiDispatcher . InvokeAsync ( Refresh ) ;
222
+ }
223
+ }
224
+
225
+ private void _fileSystemWatcher_Deleted ( object sender , FileSystemEventArgs e )
226
+ {
227
+ // the file system filter doesn't support multiple filters
228
+ if ( ! new [ ] { "cls" , "bas" , "frm" } . Contains ( e . Name . Split ( '.' ) . Last ( ) ) )
229
+ {
230
+ return ;
231
+ }
232
+
233
+ Logger . Trace ( "File system watcher detected file deleted" ) ;
234
+ if ( _messageBox . Show ( "file changed" , RubberduckUI . SourceControlPanel_Caption ,
235
+ MessageBoxButtons . OKCancel , MessageBoxIcon . Information , MessageBoxDefaultButton . Button1 ) == DialogResult . OK )
236
+ {
237
+ Provider . RemoveFile ( e . FullPath , true ) ;
238
+ UiDispatcher . InvokeAsync ( Refresh ) ;
239
+ }
240
+ }
241
+
242
+ private void _fileSystemWatcher_Created ( object sender , FileSystemEventArgs e )
243
+ {
244
+ // the file system filter doesn't support multiple filters
245
+ if ( ! new [ ] { "cls" , "bas" , "frm" } . Contains ( e . Name . Split ( '.' ) . Last ( ) ) )
246
+ {
247
+ return ;
248
+ }
249
+
250
+ Logger . Trace ( "File system watcher detected file created" ) ;
251
+ if ( _messageBox . Show ( "file changed" , RubberduckUI . SourceControlPanel_Caption ,
252
+ MessageBoxButtons . OKCancel , MessageBoxIcon . Information , MessageBoxDefaultButton . Button1 ) == DialogResult . OK )
253
+ {
254
+ Provider . AddFile ( e . FullPath ) ;
255
+ UiDispatcher . InvokeAsync ( Refresh ) ;
142
256
}
143
257
}
144
258
@@ -653,6 +767,7 @@ private void OpenRepoAssignedToProject()
653
767
654
768
private void Refresh ( )
655
769
{
770
+ _fileSystemWatcher . EnableRaisingEvents = false ;
656
771
if ( Provider == null )
657
772
{
658
773
OpenRepoAssignedToProject ( ) ;
@@ -664,6 +779,11 @@ private void Refresh()
664
779
tab . ViewModel . RefreshView ( ) ;
665
780
}
666
781
}
782
+
783
+ if ( Provider != null )
784
+ {
785
+ _fileSystemWatcher . EnableRaisingEvents = true ;
786
+ }
667
787
}
668
788
669
789
private bool ValidRepoExists ( )
@@ -824,6 +944,15 @@ public void Dispose()
824
944
{
825
945
_state . StateChanged -= _state_StateChanged ;
826
946
}
947
+
948
+ if ( _fileSystemWatcher != null )
949
+ {
950
+ _fileSystemWatcher . Created -= _fileSystemWatcher_Created ;
951
+ _fileSystemWatcher . Deleted -= _fileSystemWatcher_Deleted ;
952
+ _fileSystemWatcher . Renamed -= _fileSystemWatcher_Renamed ;
953
+ _fileSystemWatcher . Changed -= _fileSystemWatcher_Changed ;
954
+ _fileSystemWatcher . Dispose ( ) ;
955
+ }
827
956
}
828
957
}
829
958
}
0 commit comments