source: branches/2839_HiveProjectManagement/HeuristicLab.Data.Views/3.3/Path Views/TextFileView.cs @ 16057

Last change on this file since 16057 was 16057, checked in by jkarder, 15 months ago

#2839:

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