Remove excessive shortcut key matching in ToolStrip
[mono.git] / mcs / class / System / System.IO / DefaultWatcher.cs
1 // 
2 // System.IO.DefaultWatcher.cs: default IFileWatcher
3 //
4 // Authors:
5 //      Gonzalo Paniagua Javier (gonzalo@ximian.com)
6 //
7 // (c) 2004 Novell, Inc. (http://www.novell.com)
8 //
9
10 //
11 // Permission is hereby granted, free of charge, to any person obtaining
12 // a copy of this software and associated documentation files (the
13 // "Software"), to deal in the Software without restriction, including
14 // without limitation the rights to use, copy, modify, merge, publish,
15 // distribute, sublicense, and/or sell copies of the Software, and to
16 // permit persons to whom the Software is furnished to do so, subject to
17 // the following conditions:
18 // 
19 // The above copyright notice and this permission notice shall be
20 // included in all copies or substantial portions of the Software.
21 // 
22 // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
23 // EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
24 // MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
25 // NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
26 // LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
27 // OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
28 // WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
29 //
30
31 using System;
32 using System.Collections;
33 using System.IO;
34 using System.Threading;
35
36 namespace System.IO {
37         class DefaultWatcherData {
38                 public FileSystemWatcher FSW;
39                 public string Directory;
40                 public string FileMask; // If NoWildcards, contains the full path to the file.
41                 public bool IncludeSubdirs;
42                 public bool Enabled;
43                 public bool NoWildcards;
44                 public DateTime DisabledTime;
45                 public Hashtable Files;
46         }
47
48         class FileData {
49                 public string Directory;
50                 public FileAttributes Attributes;
51                 public bool NotExists;
52                 public DateTime CreationTime;
53                 public DateTime LastWriteTime;
54         }
55
56         class DefaultWatcher : IFileWatcher
57         {
58                 static DefaultWatcher instance;
59                 static Thread thread;
60                 static Hashtable watches;
61
62                 private DefaultWatcher ()
63                 {
64                 }
65                 
66                 // Locked by caller
67                 public static bool GetInstance (out IFileWatcher watcher)
68                 {
69                         if (instance != null) {
70                                 watcher = instance;
71                                 return true;
72                         }
73
74                         instance = new DefaultWatcher ();
75                         watcher = instance;
76                         return true;
77                 }
78                 
79                 public void StartDispatching (FileSystemWatcher fsw)
80                 {
81                         DefaultWatcherData data;
82                         lock (this) {
83                                 if (watches == null)
84                                         watches = new Hashtable ();
85
86                                 if (thread == null) {
87                                         thread = new Thread (new ThreadStart (Monitor));
88                                         thread.IsBackground = true;
89                                         thread.Start ();
90                                 }
91                         }
92
93                         lock (watches) {
94                                 data = (DefaultWatcherData) watches [fsw];
95                                 if (data == null) {
96                                         data = new DefaultWatcherData ();
97                                         data.Files = new Hashtable ();
98                                         watches [fsw] = data;
99                                 }
100
101                                 data.FSW = fsw;
102                                 data.Directory = fsw.FullPath;
103                                 data.NoWildcards = !fsw.Pattern.HasWildcard;
104                                 if (data.NoWildcards)
105                                         data.FileMask = Path.Combine (data.Directory, fsw.MangledFilter);
106                                 else
107                                         data.FileMask = fsw.MangledFilter;
108
109                                 data.IncludeSubdirs = fsw.IncludeSubdirectories;
110                                 data.Enabled = true;
111                                 data.DisabledTime = DateTime.MaxValue;
112                                 UpdateDataAndDispatch (data, false);
113                         }
114                 }
115
116                 public void StopDispatching (FileSystemWatcher fsw)
117                 {
118                         DefaultWatcherData data;
119                         lock (this) {
120                                 if (watches == null) return;
121                         }
122                         
123                         lock (watches) {
124                                 data = (DefaultWatcherData) watches [fsw];
125                                 if (data != null) {
126                                         data.Enabled = false;
127                                         data.DisabledTime = DateTime.Now;
128                                 }
129                         }
130                 }
131
132
133                 void Monitor ()
134                 {
135                         int zeroes = 0;
136
137                         while (true) {
138                                 Thread.Sleep (750);
139                                 
140                                 Hashtable my_watches;
141                                 lock (watches) {
142                                         if (watches.Count == 0) {
143                                                 if (++zeroes == 20)
144                                                         break;
145                                                 continue;
146                                         }
147                                         
148                                         my_watches = (Hashtable) watches.Clone ();
149                                 }
150                                 
151                                 if (my_watches.Count != 0) {
152                                         zeroes = 0;
153                                         foreach (DefaultWatcherData data in my_watches.Values) {
154                                                 bool remove = UpdateDataAndDispatch (data, true);
155                                                 if (remove)
156                                                         lock (watches)
157                                                                 watches.Remove (data.FSW);
158                                         }
159                                 }
160                         }
161
162                         lock (this) {
163                                 thread = null;
164                         }
165                 }
166                 
167                 bool UpdateDataAndDispatch (DefaultWatcherData data, bool dispatch)
168                 {
169                         if (!data.Enabled) {
170                                 return (data.DisabledTime != DateTime.MaxValue &&
171                                         (DateTime.Now - data.DisabledTime).TotalSeconds > 5);
172                         }
173
174                         DoFiles (data, data.Directory, dispatch);
175                         return false;
176                 }
177
178                 static void DispatchEvents (FileSystemWatcher fsw, FileAction action, string filename)
179                 {
180                         RenamedEventArgs renamed = null;
181
182                         lock (fsw) {
183                                 fsw.DispatchEvents (action, filename, ref renamed);
184                                 if (fsw.Waiting) {
185                                         fsw.Waiting = false;
186                                         System.Threading.Monitor.PulseAll (fsw);
187                                 }
188                         }
189                 }
190
191                 static string [] NoStringsArray = new string [0];
192                 void DoFiles (DefaultWatcherData data, string directory, bool dispatch)
193                 {
194                         bool direxists = Directory.Exists (directory);
195                         if (direxists && data.IncludeSubdirs) {
196                                 foreach (string d in Directory.GetDirectories (directory))
197                                         DoFiles (data, d, dispatch);
198                         }
199
200                         string [] files = null;
201                         if (!direxists) {
202                                 files = NoStringsArray;
203                         } else if (!data.NoWildcards) {
204                                 files = Directory.GetFileSystemEntries (directory, data.FileMask);
205                         } else {
206                                 // The pattern does not have wildcards
207                                 if (File.Exists (data.FileMask) || Directory.Exists (data.FileMask))
208                                         files = new string [] { data.FileMask };
209                                 else
210                                         files = NoStringsArray;
211                         }
212
213                         /* Set all as untested */
214                         foreach (string filename in data.Files.Keys) {
215                                 FileData fd = (FileData) data.Files [filename];
216                                 if (fd.Directory == directory)
217                                         fd.NotExists = true;
218                         }
219
220                         /* New files */
221                         foreach (string filename in files) {
222                                 FileData fd = (FileData) data.Files [filename];
223                                 if (fd == null) {
224                                         try {
225                                                 data.Files.Add (filename, CreateFileData (directory, filename));
226                                         } catch {
227                                                 // The file might have been removed in the meanwhile
228                                                 data.Files.Remove (filename);
229                                                 continue;
230                                         }
231                                         
232                                         if (dispatch)
233                                                 DispatchEvents (data.FSW, FileAction.Added, filename);
234                                 } else if (fd.Directory == directory) {
235                                         fd.NotExists = false;
236                                 }
237                         }
238
239                         if (!dispatch) // We only initialize the file list
240                                 return;
241
242                         /* Removed files */
243                         ArrayList removed = null;
244                         foreach (string filename in data.Files.Keys) {
245                                 FileData fd = (FileData) data.Files [filename];
246                                 if (fd.NotExists) {
247                                         if (removed == null)
248                                                 removed = new ArrayList ();
249
250                                         removed.Add (filename);
251                                         DispatchEvents (data.FSW, FileAction.Removed, filename);
252                                 }
253                         }
254
255                         if (removed != null) {
256                                 foreach (string filename in removed)
257                                         data.Files.Remove (filename);
258
259                                 removed = null;
260                         }
261
262                         /* Changed files */
263                         foreach (string filename in data.Files.Keys) {
264                                 FileData fd = (FileData) data.Files [filename];
265                                 DateTime creation, write;
266                                 try {
267                                         creation = File.GetCreationTime (filename);
268                                         write = File.GetLastWriteTime (filename);
269                                 } catch {
270                                         /* Deleted */
271                                         if (removed == null)
272                                                 removed = new ArrayList ();
273
274                                         removed.Add (filename);
275                                         DispatchEvents (data.FSW, FileAction.Removed, filename);
276                                         continue;
277                                 }
278                                 
279                                 if (creation != fd.CreationTime || write != fd.LastWriteTime) {
280                                         fd.CreationTime = creation;
281                                         fd.LastWriteTime = write;
282                                         DispatchEvents (data.FSW, FileAction.Modified, filename);
283                                 }
284                         }
285
286                         if (removed != null) {
287                                 foreach (string filename in removed)
288                                         data.Files.Remove (filename);
289                         }
290
291                 }
292
293                 static FileData CreateFileData (string directory, string filename)
294                 {
295                         FileData fd = new FileData ();
296                         string fullpath = Path.Combine (directory, filename);
297                         fd.Directory = directory;
298                         fd.Attributes = File.GetAttributes (fullpath);
299                         fd.CreationTime = File.GetCreationTime (fullpath);
300                         fd.LastWriteTime = File.GetLastWriteTime (fullpath);
301                         return fd;
302                 }
303         }
304 }
305