source: stable/HeuristicLab.Data.Views/3.3/Path Views/TextFileView.cs @ 9961

Last change on this file since 9961 was 9961, checked in by mkommend, 8 years ago

#2081: Merged path data types into stable.

File size: 9.1 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;
27using HeuristicLab.PluginInfrastructure;
28
29namespace HeuristicLab.Data.Views {
30  [View("TextFileView")]
31  [Content(typeof(TextFileValue), true)]
32  public sealed partial class TextFileView : FileValueView {
33    private bool fileContentChanged;
34    private bool FileContentChanged {
35      get { return fileContentChanged; }
36      set {
37        if (fileContentChanged != value) {
38          fileContentChanged = value;
39          OnFileContentChanged();
40        }
41      }
42    }
43
44    public new TextFileValue Content {
45      get { return (TextFileValue)base.Content; }
46      set { base.Content = value; }
47    }
48
49    public TextFileView() {
50      InitializeComponent();
51      fileContentChanged = false;
52    }
53
54    protected override void RegisterContentEvents() {
55      base.RegisterContentEvents();
56      Content.StringValue.ValueChanged += Content_FilePathChanged;
57    }
58    protected override void DeregisterContentEvents() {
59      Content.StringValue.ValueChanged -= Content_FilePathChanged;
60      fileSystemWatcher.EnableRaisingEvents = false;
61      base.DeregisterContentEvents();
62    }
63    protected override void SetEnabledStateOfControls() {
64      base.SetEnabledStateOfControls();
65      textBox.ReadOnly = Locked || ReadOnly || Content == null;
66      saveButton.Enabled = !Locked && !ReadOnly && Content != null && FileContentChanged;
67
68      if (Content != null && Content.Exists()) {
69        fileSystemWatcher.Filter = Path.GetFileName(Content.Value);
70        fileSystemWatcher.Path = Path.GetDirectoryName(Content.Value);
71      }
72      fileSystemWatcher.EnableRaisingEvents = Content != null && File.Exists(Content.Value) && Visible;
73    }
74
75    protected override void OnVisibleChanged(EventArgs e) {
76      //mkommend: necessary to update the textbox to detect intermediate file changes.
77      if (Visible && Content != null) UpdateTextBox();
78      base.OnVisibleChanged(e);
79    }
80
81    protected override void OnContentChanged() {
82      base.OnContentChanged();
83      FileContentChanged = false;
84      if (Content == null) {
85        textBox.Text = string.Empty;
86        //mkommend: other properties of the file system watcher cannot be cleared (e.g., path) as this leads to an ArgumentException
87        fileSystemWatcher.EnableRaisingEvents = false;
88        return;
89      }
90      saveFileDialog.Filter = Content.FileDialogFilter;
91      UpdateTextBox();
92    }
93
94    private void Content_FilePathChanged(object sender, EventArgs e) {
95      UpdateTextBox();
96      SetEnabledStateOfControls();
97    }
98
99    private void textBox_TextChanged(object sender, EventArgs e) {
100      FileContentChanged = fileText != textBox.Text;
101    }
102
103    private void OnFileContentChanged() {
104      SetEnabledStateOfControls();
105      textBox.ForeColor = FileContentChanged ? Color.Red : Color.Black;
106    }
107
108    private bool fileSystemWatcherChangedFired = false;
109    private void fileSystemWatcher_Changed(object sender, FileSystemEventArgs e) {
110      //mkommend: cannot react on visible changed, because this event is not fired when the parent control gets visible set to false
111      if (!Visible) return;
112      //FileSystemWatcher may fire multiple events depending on how file changes are implemented in the modifying program
113      //see: http://stackoverflow.com/questions/1764809/filesystemwatcher-changed-event-is-raised-twice
114      if (fileSystemWatcherChangedFired) return;
115      fileSystemWatcherChangedFired = true;
116
117      string newContent = ReadFile(Content.Value);
118      if (newContent == textBox.Text) {
119        fileSystemWatcherChangedFired = false;
120        return;
121      }
122
123      //File created
124      if (e.ChangeType == WatcherChangeTypes.Created) {
125        UpdateTextBox();
126      }
127
128      //File changed
129      else if (e.ChangeType == WatcherChangeTypes.Changed) {
130        string msg = string.Format("The content of the file \"{0}\" has changed.\nDo you want to reload the file?", Content.Value);
131        var result = MessageBox.Show(this, msg, "Reload the file?", MessageBoxButtons.YesNo, MessageBoxIcon.Information);
132        if (result == DialogResult.Yes) {
133          UpdateTextBox();
134        } else {
135          fileText = newContent;
136          FileContentChanged = true;
137        }
138      }
139
140      //File deleted
141      else if (e.ChangeType == WatcherChangeTypes.Deleted) {
142        string msg = string.Format("The file \"{0}\" is not present anymore. Do you want to restore the file from the given content?", Content.Value);
143        var result = MessageBox.Show(this, msg, "Restore file?", MessageBoxButtons.YesNo, MessageBoxIcon.Warning);
144        if (result == DialogResult.Yes) {
145          SaveFile();
146        }
147        UpdateTextBox();
148      }
149      fileSystemWatcherChangedFired = false;
150    }
151
152    private void fileSystemWatcher_Renamed(object sender, RenamedEventArgs e) {
153      //mkommend: cannot react on visible changed, because this event is not fired when the parent control gets visible set to false
154      if (!Visible) return;
155      string msg = string.Format("The file \"{0}\" got renamed to \"{1}\". Do you want to update the file path?", e.OldName, e.Name);
156      var result = MessageBox.Show(this, msg, "Update file path?", MessageBoxButtons.YesNo, MessageBoxIcon.Information);
157      if (result == DialogResult.Yes) {
158        Content.Value = e.FullPath;
159        fileSystemWatcher.Filter = e.Name;
160      }
161      UpdateTextBox();
162    }
163
164    private void SaveFile() {
165      //omit circular events by changing the file from HL
166      fileSystemWatcher.EnableRaisingEvents = false;
167      string path = Content.Value;
168      if (string.IsNullOrEmpty(path)) {
169        if (saveFileDialog.ShowDialog(this) != DialogResult.OK) return;
170        path = saveFileDialog.FileName;
171      }
172
173      WriteFile(path, textBox.Text);
174      Content.Value = path;
175      FileContentChanged = false;
176      fileSystemWatcher.EnableRaisingEvents = true;
177    }
178
179    private void saveButton_Click(object sender, EventArgs e) {
180      SaveFile();
181    }
182
183    private string fileText;
184    private void UpdateTextBox() {
185      if (string.IsNullOrEmpty(Content.Value)) {
186        textBox.Enabled = false;
187        textBox.Text = string.Format("No file path is specified.");
188        return;
189      }
190
191      fileText = ReadFile(Content.Value);
192      if (fileText == null) {
193        textBox.Enabled = false;
194        textBox.Text = string.Format("The specified file \"{0}\" cannot be found.", Content.Value);
195        return;
196      }
197
198      textBox.Enabled = true;
199      textBox.Text = fileText;
200    }
201    private void textBox_Validated(object sender, EventArgs e) {
202      if (!FileContentChanged) return;
203      string msg = string.Format("You have not saved the changes in the file \"{0}\" yet. Do you want to save the changes?", Content.Value);
204      var result = MessageBox.Show(this, msg, "Save changes?", MessageBoxButtons.YesNo, MessageBoxIcon.Information);
205      if (result == DialogResult.Yes) SaveFile();
206    }
207
208    protected override bool ProcessCmdKey(ref Message msg, Keys keyData) {
209      if (keyData == (Keys.Control | Keys.S)) {
210        SaveFile();
211        return true;
212      }
213      return base.ProcessCmdKey(ref msg, keyData);
214    }
215
216    private static string ReadFile(string path) {
217      if (!File.Exists(path)) return null;
218      string fileContent = string.Empty;
219      try {
220        using (FileStream fileStream = new FileStream(path, FileMode.Open, FileAccess.Read, FileShare.ReadWrite)) {
221          using (StreamReader streamReader = new StreamReader(fileStream)) {
222            fileContent = streamReader.ReadToEnd();
223          }
224        }
225      }
226      catch (Exception e) {
227        ErrorHandling.ShowErrorDialog(e);
228      }
229      return fileContent;
230    }
231
232    private static void WriteFile(string path, string fileContent) {
233      try {
234        using (FileStream fileStream = new FileStream(path, FileMode.Create, FileAccess.Write, FileShare.None)) {
235          using (StreamWriter streamWriter = new StreamWriter(fileStream)) {
236            streamWriter.Write(fileContent);
237          }
238        }
239      }
240      catch (Exception e) {
241        ErrorHandling.ShowErrorDialog(e);
242      }
243    }
244  }
245}
Note: See TracBrowser for help on using the repository browser.