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

Last change on this file since 9714 was 9714, checked in by mkommend, 6 years ago

#2081: Integrated new HL path data types from the branch.

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