Free cookie consent management tool by TermsFeed Policy Generator

source: trunk/sources/HeuristicLab.Data.Views/3.3/Path Views/TextFileView.cs @ 9841

Last change on this file since 9841 was 9841, checked in by mkommend, 11 years ago

#2081: Changed FileShare to read / write for file reloading.

File size: 8.8 KB
Line 
1#region License Information
2/* HeuristicLab
3 * Copyright (C) 2002-2013 Heuristic and Evolutionary Algorithms Laboratory (HEAL)
4 *
5 * This file is part of HeuristicLab.
6 *
7 * HeuristicLab is free software: you can redistribute it and/or modify
8 * it under the terms of the GNU General Public License as published by
9 * the Free Software Foundation, either version 3 of the License, or
10 * (at your option) any later version.
11 *
12 * HeuristicLab is distributed in the hope that it will be useful,
13 * but WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
15 * GNU General Public License for more details.
16 *
17 * You should have received a copy of the GNU General Public License
18 * along with HeuristicLab. If not, see <http://www.gnu.org/licenses/>.
19 */
20#endregion
21
22using System;
23using System.Drawing;
24using System.IO;
25using System.Windows.Forms;
26using HeuristicLab.MainForm;
27
28namespace HeuristicLab.Data.Views {
29  [View("TextFileView")]
30  [Content(typeof(TextFileValue), true)]
31  public sealed partial class TextFileView : FileValueView {
32    private bool fileContentChanged;
33    private bool FileContentChanged {
34      get { return fileContentChanged; }
35      set {
36        if (fileContentChanged != value) {
37          fileContentChanged = value;
38          OnFileContentChanged();
39        }
40      }
41    }
42
43    public new TextFileValue Content {
44      get { return (TextFileValue)base.Content; }
45      set { base.Content = value; }
46    }
47
48    public TextFileView() {
49      InitializeComponent();
50      fileContentChanged = false;
51    }
52
53    protected override void RegisterContentEvents() {
54      base.RegisterContentEvents();
55      Content.StringValue.ValueChanged += Content_FilePathChanged;
56    }
57    protected override void DeregisterContentEvents() {
58      Content.StringValue.ValueChanged -= Content_FilePathChanged;
59      fileSystemWatcher.EnableRaisingEvents = false;
60      base.DeregisterContentEvents();
61    }
62    protected override void SetEnabledStateOfControls() {
63      base.SetEnabledStateOfControls();
64      textBox.ReadOnly = Locked || ReadOnly || Content == null;
65      saveButton.Enabled = !Locked && !ReadOnly && Content != null && FileContentChanged;
66
67      if (Content != null && Content.Exists()) {
68        fileSystemWatcher.Filter = Path.GetFileName(Content.Value);
69        fileSystemWatcher.Path = Path.GetDirectoryName(Content.Value);
70      }
71      fileSystemWatcher.EnableRaisingEvents = Content != null && File.Exists(Content.Value) && Visible;
72    }
73
74    protected override void OnVisibleChanged(EventArgs e) {
75      //mkommend: necessary to update the textbox to detect intermediate file changes.
76      if (Visible && Content != null) UpdateTextBox();
77      base.OnVisibleChanged(e);
78    }
79
80    protected override void OnContentChanged() {
81      base.OnContentChanged();
82      FileContentChanged = false;
83      if (Content == null) {
84        textBox.Text = string.Empty;
85        //mkommend: other properties of the file system watcher cannot be cleared (e.g., path) as this leads to an ArgumentException
86        fileSystemWatcher.EnableRaisingEvents = false;
87        return;
88      }
89      saveFileDialog.Filter = Content.FileDialogFilter;
90      UpdateTextBox();
91    }
92
93    private void Content_FilePathChanged(object sender, EventArgs e) {
94      UpdateTextBox();
95      SetEnabledStateOfControls();
96    }
97
98    private void textBox_TextChanged(object sender, EventArgs e) {
99      FileContentChanged = fileText != textBox.Text;
100    }
101
102    private void OnFileContentChanged() {
103      SetEnabledStateOfControls();
104      textBox.ForeColor = FileContentChanged ? Color.Red : Color.Black;
105    }
106
107    private bool fileSystemWatcherChangedFired = false;
108    private void fileSystemWatcher_Changed(object sender, FileSystemEventArgs e) {
109      //mkommend: cannot react on visible changed, because this event is not fired when the parent control gets visible set to false
110      if (!Visible) return;
111      //FileSystemWatcher may fire multiple events depending on how file changes are implemented in the modifying program
112      //see: http://stackoverflow.com/questions/1764809/filesystemwatcher-changed-event-is-raised-twice
113      if (fileSystemWatcherChangedFired) return;
114      fileSystemWatcherChangedFired = true;
115
116      string newContent = ReadFile(Content.Value);
117      if (newContent == textBox.Text) {
118        fileSystemWatcherChangedFired = false;
119        return;
120      }
121
122      //File created
123      if (e.ChangeType == WatcherChangeTypes.Created) {
124        UpdateTextBox();
125      }
126
127      //File changed
128      else if (e.ChangeType == WatcherChangeTypes.Changed) {
129        string msg = string.Format("The content of the file \"{0}\" has changed.\nDo you want to reload the file?", Content.Value);
130        var result = MessageBox.Show(this, msg, "Reload the file?", MessageBoxButtons.YesNo, MessageBoxIcon.Information);
131        if (result == DialogResult.Yes) {
132          UpdateTextBox();
133        } else {
134          fileText = newContent;
135          FileContentChanged = true;
136        }
137      }
138
139      //File deleted
140      else if (e.ChangeType == WatcherChangeTypes.Deleted) {
141        string msg = string.Format("The file \"{0}\" is not present anymore. Do you want to restore the file from the given content?", Content.Value);
142        var result = MessageBox.Show(this, msg, "Restore file?", MessageBoxButtons.YesNo, MessageBoxIcon.Warning);
143        if (result == DialogResult.Yes) {
144          SaveFile();
145        }
146        UpdateTextBox();
147      }
148      fileSystemWatcherChangedFired = false;
149    }
150
151    private void fileSystemWatcher_Renamed(object sender, RenamedEventArgs e) {
152      //mkommend: cannot react on visible changed, because this event is not fired when the parent control gets visible set to false
153      if (!Visible) return;
154      string msg = string.Format("The file \"{0}\" got renamed to \"{1}\". Do you want to update the file path?", e.OldName, e.Name);
155      var result = MessageBox.Show(this, msg, "Update file path?", MessageBoxButtons.YesNo, MessageBoxIcon.Information);
156      if (result == DialogResult.Yes) {
157        Content.Value = e.FullPath;
158        fileSystemWatcher.Filter = e.Name;
159      }
160      UpdateTextBox();
161    }
162
163    private void SaveFile() {
164      //omit circular events by changing the file from HL
165      fileSystemWatcher.EnableRaisingEvents = false;
166      string path = Content.Value;
167      if (string.IsNullOrEmpty(path)) {
168        if (saveFileDialog.ShowDialog(this) != DialogResult.OK) return;
169        path = saveFileDialog.FileName;
170      }
171
172      WriteFile(path, textBox.Text);
173      Content.Value = path;
174      FileContentChanged = false;
175      fileSystemWatcher.EnableRaisingEvents = true;
176    }
177
178    private void saveButton_Click(object sender, EventArgs e) {
179      SaveFile();
180    }
181
182    private string fileText;
183    private void UpdateTextBox() {
184      if (string.IsNullOrEmpty(Content.Value)) {
185        textBox.Enabled = false;
186        textBox.Text = string.Format("No file path is specified.");
187        return;
188      }
189
190      fileText = ReadFile(Content.Value);
191      if (fileText == null) {
192        textBox.Enabled = false;
193        textBox.Text = string.Format("The specified file \"{0}\" cannot be found.", Content.Value);
194        return;
195      }
196
197      textBox.Enabled = true;
198      textBox.Text = fileText;
199    }
200    private void textBox_Validated(object sender, EventArgs e) {
201      if (!FileContentChanged) return;
202      string msg = string.Format("You have not saved the changes in the file \"{0}\" yet. Do you want to save the changes?", Content.Value);
203      var result = MessageBox.Show(this, msg, "Save changes?", MessageBoxButtons.YesNo, MessageBoxIcon.Information);
204      if (result == DialogResult.Yes) SaveFile();
205    }
206
207    protected override bool ProcessCmdKey(ref Message msg, Keys keyData) {
208      if (keyData == (Keys.Control | Keys.S)) {
209        SaveFile();
210        return true;
211      }
212      return base.ProcessCmdKey(ref msg, keyData);
213    }
214
215    private static string ReadFile(string path) {
216      if (!File.Exists(path)) return null;
217      string fileContent = string.Empty;
218      using (FileStream fileStream = new FileStream(path, FileMode.Open, FileAccess.Read, FileShare.ReadWrite)) {
219        using (StreamReader streamReader = new StreamReader(fileStream)) {
220          fileContent = streamReader.ReadToEnd();
221        }
222      }
223      return fileContent;
224    }
225
226    private static void WriteFile(string path, string fileContent) {
227      using (FileStream fileStream = new FileStream(path, FileMode.Create, FileAccess.Write, FileShare.None)) {
228        using (StreamWriter streamWriter = new StreamWriter(fileStream)) {
229          streamWriter.Write(fileContent);
230        }
231      }
232    }
233  }
234}
Note: See TracBrowser for help on using the repository browser.