diff --git a/src/AddIns/BackendBindings/Scripting/Test/Utils/MockViewContent.cs b/src/AddIns/BackendBindings/Scripting/Test/Utils/MockViewContent.cs index 63c062ea2c..c571024080 100644 --- a/src/AddIns/BackendBindings/Scripting/Test/Utils/MockViewContent.cs +++ b/src/AddIns/BackendBindings/Scripting/Test/Utils/MockViewContent.cs @@ -26,6 +26,7 @@ namespace ICSharpCode.Scripting.Tests.Utils public event EventHandler TabPageTextChanged; public event EventHandler Disposed; public event EventHandler IsDirtyChanged; + public event EventHandler IsReadOnlyChanged; public string TitleName { get { @@ -234,6 +235,13 @@ namespace ICSharpCode.Scripting.Tests.Utils } } + protected virtual void OnIsReadOnlyChanged(EventArgs e) + { + if (IsReadOnlyChanged != null) { + IsReadOnlyChanged(this, e); + } + } + public object GetService(Type serviceType) { return null; diff --git a/src/AddIns/BackendBindings/WixBinding/Test/Utils/MockViewContent.cs b/src/AddIns/BackendBindings/WixBinding/Test/Utils/MockViewContent.cs index f46e5dfc15..759927190b 100644 --- a/src/AddIns/BackendBindings/WixBinding/Test/Utils/MockViewContent.cs +++ b/src/AddIns/BackendBindings/WixBinding/Test/Utils/MockViewContent.cs @@ -41,6 +41,7 @@ namespace WixBinding.Tests.Utils public event EventHandler IsDirtyChanged; public event EventHandler TitleNameChanged; public event EventHandler InfoTipChanged; + public event EventHandler IsReadOnlyChanged; #pragma warning restore 67 public IList Files { diff --git a/src/AddIns/BackendBindings/WixBinding/Test/Utils/MockWorkbenchWindow.cs b/src/AddIns/BackendBindings/WixBinding/Test/Utils/MockWorkbenchWindow.cs index 2c1bf2b49a..60eef0e0cd 100644 --- a/src/AddIns/BackendBindings/WixBinding/Test/Utils/MockWorkbenchWindow.cs +++ b/src/AddIns/BackendBindings/WixBinding/Test/Utils/MockWorkbenchWindow.cs @@ -86,10 +86,5 @@ namespace WixBinding.Tests.Utils TitleChanged(this, e); } } - - public void RefreshStatus() - { - throw new NotImplementedException(); - } } } diff --git a/src/AddIns/DisplayBindings/AvalonEdit.AddIn/Src/AvalonEditViewContent.cs b/src/AddIns/DisplayBindings/AvalonEdit.AddIn/Src/AvalonEditViewContent.cs index 39fad952bd..fff266648c 100644 --- a/src/AddIns/DisplayBindings/AvalonEdit.AddIn/Src/AvalonEditViewContent.cs +++ b/src/AddIns/DisplayBindings/AvalonEdit.AddIn/Src/AvalonEditViewContent.cs @@ -5,15 +5,12 @@ using System; using System.IO; using System.Linq; using System.Text; -using System.Windows.Threading; + using ICSharpCode.AvalonEdit.AddIn.Options; -using ICSharpCode.AvalonEdit.Document; using ICSharpCode.AvalonEdit.Highlighting; -using ICSharpCode.AvalonEdit.Utils; using ICSharpCode.Core; using ICSharpCode.SharpDevelop; using ICSharpCode.SharpDevelop.Bookmarks; -using ICSharpCode.SharpDevelop.Dom; using ICSharpCode.SharpDevelop.Editor; using ICSharpCode.SharpDevelop.Gui; using ICSharpCode.SharpDevelop.Project; @@ -53,6 +50,21 @@ namespace ICSharpCode.AvalonEdit.AddIn codeEditor.Document.UndoStack.PropertyChanged += codeEditor_Document_UndoStack_PropertyChanged; codeEditor.CaretPositionChanged += CaretChanged; codeEditor.TextCopied += codeEditor_TextCopied; + + // get the watcher for the file + var watcher = FileChangeWatcher.ActiveWatchers.FirstOrDefault(w => w.File == file); + if (watcher != null) + watcher.FileChanged += OnFileExternallyChanged; + } + + void OnFileExternallyChanged(object sender, EventArgs e) + { + // handle readonly + bool isExternalReadOnly = (File.GetAttributes(this.PrimaryFileName) & FileAttributes.ReadOnly) == FileAttributes.ReadOnly; + if (isExternalReadOnly != IsReadOnly) { + codeEditor.PrimaryTextEditor.IsReadOnly = isExternalReadOnly; + OnIsReadOnlyChanged(EventArgs.Empty); + } } void codeEditor_Document_UndoStack_PropertyChanged(object sender, System.ComponentModel.PropertyChangedEventArgs e) @@ -139,6 +151,10 @@ namespace ICSharpCode.AvalonEdit.AddIn codeEditor.SyntaxHighlighting = HighlightingManager.Instance.GetDefinitionByExtension(Path.GetExtension(file.FileName)); + if (!file.IsUntitled) { + codeEditor.PrimaryTextEditor.IsReadOnly = (File.GetAttributes(file.FileName) & FileAttributes.ReadOnly) == FileAttributes.ReadOnly; + } + codeEditor.Load(stream); // Load() causes the undo stack to think stuff changed, so re-mark the file as original if necessary if (!this.PrimaryFile.IsDirty) { diff --git a/src/AddIns/DisplayBindings/AvalonEdit.AddIn/Src/CodeEditorView.cs b/src/AddIns/DisplayBindings/AvalonEdit.AddIn/Src/CodeEditorView.cs index f3b3f10e69..e9921205be 100755 --- a/src/AddIns/DisplayBindings/AvalonEdit.AddIn/Src/CodeEditorView.cs +++ b/src/AddIns/DisplayBindings/AvalonEdit.AddIn/Src/CodeEditorView.cs @@ -84,21 +84,6 @@ namespace ICSharpCode.AvalonEdit.AddIn get { return this.Adapter.FileName; } } - public new bool IsReadOnly { - get { - if (!File.Exists(FileName)) - return base.IsReadOnly; - - if ((File.GetAttributes(FileName) & FileAttributes.ReadOnly) == FileAttributes.ReadOnly) - return true; - - return base.IsReadOnly; - } - set { - base.IsReadOnly = value; - } - } - protected override void OnOptionChanged(PropertyChangedEventArgs e) { base.OnOptionChanged(e); diff --git a/src/AddIns/DisplayBindings/XmlEditor/Test/Utils/MockViewContent.cs b/src/AddIns/DisplayBindings/XmlEditor/Test/Utils/MockViewContent.cs index dc81f5cc3c..426b0fa041 100644 --- a/src/AddIns/DisplayBindings/XmlEditor/Test/Utils/MockViewContent.cs +++ b/src/AddIns/DisplayBindings/XmlEditor/Test/Utils/MockViewContent.cs @@ -53,6 +53,15 @@ namespace XmlEditor.Tests.Utils } } + public event EventHandler IsReadOnlyChanged; + + protected virtual void OnIsReadOnlyChanged(EventArgs e) + { + if (IsReadOnlyChanged != null) { + IsReadOnlyChanged(this, e); + } + } + public object Control { get { throw new NotImplementedException(); diff --git a/src/AddIns/Misc/Reports/ICSharpCode.Reports.Addin/Test/Designer/MockViewContend.cs b/src/AddIns/Misc/Reports/ICSharpCode.Reports.Addin/Test/Designer/MockViewContend.cs index 468ed8876c..c4318d0603 100644 --- a/src/AddIns/Misc/Reports/ICSharpCode.Reports.Addin/Test/Designer/MockViewContend.cs +++ b/src/AddIns/Misc/Reports/ICSharpCode.Reports.Addin/Test/Designer/MockViewContend.cs @@ -28,6 +28,7 @@ namespace ICSharpCode.Reports.Addin.Test.Designer public event EventHandler TabPageTextChanged; public event EventHandler Disposed; public event EventHandler IsDirtyChanged; + public event EventHandler IsReadOnlyChanged; public object Control { @@ -230,6 +231,13 @@ namespace ICSharpCode.Reports.Addin.Test.Designer } } + protected virtual void OnIsReadOnlyChanged(EventArgs e) + { + if (IsReadOnlyChanged != null) { + IsReadOnlyChanged(this, e); + } + } + public object InitiallyFocusedControl { get { throw new NotImplementedException(); diff --git a/src/Main/Base/Project/Src/Gui/AbstractViewContent.cs b/src/Main/Base/Project/Src/Gui/AbstractViewContent.cs index 121abe3c91..03bd333ac5 100644 --- a/src/Main/Base/Project/Src/Gui/AbstractViewContent.cs +++ b/src/Main/Base/Project/Src/Gui/AbstractViewContent.cs @@ -2,11 +2,10 @@ // This code is distributed under the GNU LGPL (for details please see \doc\license.txt) using System; -using System.ComponentModel.Design; using System.Collections.Generic; using System.Collections.ObjectModel; +using System.ComponentModel.Design; using System.IO; -using System.Windows.Forms; using ICSharpCode.Core; using ICSharpCode.Core.Presentation; @@ -393,7 +392,6 @@ namespace ICSharpCode.SharpDevelop.Gui } #endregion - #region InfoTip public event EventHandler InfoTipChanged; @@ -608,6 +606,7 @@ namespace ICSharpCode.SharpDevelop.Gui return null; } + #region Read only /// /// Gets if the view content is read-only (can be saved only when choosing another file name). /// @@ -615,6 +614,16 @@ namespace ICSharpCode.SharpDevelop.Gui get { return false; } } + public event EventHandler IsReadOnlyChanged; + + protected virtual void OnIsReadOnlyChanged(EventArgs e) + { + if (IsReadOnlyChanged != null) { + IsReadOnlyChanged(this, e); + } + } + #endregion + /// /// Gets if the view content is view-only (cannot be saved at all). /// diff --git a/src/Main/Base/Project/Src/Gui/IViewContent.cs b/src/Main/Base/Project/Src/Gui/IViewContent.cs index ec18b3f5c3..05f420334c 100644 --- a/src/Main/Base/Project/Src/Gui/IViewContent.cs +++ b/src/Main/Base/Project/Src/Gui/IViewContent.cs @@ -145,6 +145,11 @@ namespace ICSharpCode.SharpDevelop.Gui /// bool IsReadOnly { get; } + /// + /// Is called each time the IsReadonly for the content has changed. + /// + event EventHandler IsReadOnlyChanged; + /// /// Gets if the view content is view-only (cannot be saved at all). /// diff --git a/src/Main/Base/Project/Src/Gui/IWorkbenchWindow.cs b/src/Main/Base/Project/Src/Gui/IWorkbenchWindow.cs index d03d264888..3218d98a35 100644 --- a/src/Main/Base/Project/Src/Gui/IWorkbenchWindow.cs +++ b/src/Main/Base/Project/Src/Gui/IWorkbenchWindow.cs @@ -72,11 +72,6 @@ namespace ICSharpCode.SharpDevelop.Gui /// void SelectWindow(); - /// - /// Refresh window status: title, infotip, lock. - /// - void RefreshStatus(); - /// /// Is called when the title of this window has changed. /// diff --git a/src/Main/Base/Project/Src/Gui/Workbench/Layouts/AvalonWorkbenchWindow.cs b/src/Main/Base/Project/Src/Gui/Workbench/Layouts/AvalonWorkbenchWindow.cs index 6116674c50..a8e10c1d35 100644 --- a/src/Main/Base/Project/Src/Gui/Workbench/Layouts/AvalonWorkbenchWindow.cs +++ b/src/Main/Base/Project/Src/Gui/Workbench/Layouts/AvalonWorkbenchWindow.cs @@ -145,8 +145,10 @@ namespace ICSharpCode.SharpDevelop.Gui UpdateTitleAndInfoTip(); IViewContent newActiveViewContent = this.ActiveViewContent; - if (newActiveViewContent != null) + if (newActiveViewContent != null) { IsLocked = newActiveViewContent.IsReadOnly; + newActiveViewContent.IsReadOnlyChanged += delegate { IsLocked = newActiveViewContent.IsReadOnly; }; + } if (oldActiveViewContent != newActiveViewContent && ActiveViewContentChanged != null) { ActiveViewContentChanged(this, EventArgs.Empty); @@ -267,11 +269,6 @@ namespace ICSharpCode.SharpDevelop.Gui Activate();//this.SetAsActive(); } - public void RefreshStatus() - { - UpdateActiveViewContent(); - } - public override void OnApplyTemplate() { base.OnApplyTemplate(); diff --git a/src/Main/Base/Project/Src/Services/File/FileChangeWatcher.cs b/src/Main/Base/Project/Src/Services/File/FileChangeWatcher.cs index eb1de717fd..b73a8a7c9f 100644 --- a/src/Main/Base/Project/Src/Services/File/FileChangeWatcher.cs +++ b/src/Main/Base/Project/Src/Services/File/FileChangeWatcher.cs @@ -11,7 +11,7 @@ using ICSharpCode.Core; namespace ICSharpCode.SharpDevelop { - internal sealed class FileChangeWatcher : IDisposable + public sealed class FileChangeWatcher : IDisposable { public static bool DetectExternalChangesOption { get { @@ -37,6 +37,10 @@ namespace ICSharpCode.SharpDevelop static HashSet activeWatchers = new HashSet(); + public static HashSet ActiveWatchers { + get { return activeWatchers; } + } + static int globalDisableCount; public static void DisableAllChangeWatchers() @@ -57,9 +61,23 @@ namespace ICSharpCode.SharpDevelop w.SetWatcher(); } + public event EventHandler FileChanged; + + void OnFileChanged(EventArgs e) + { + if (FileChanged != null) { + FileChanged(this, e); + } + } + FileSystemWatcher watcher; bool wasChangedExternally = false; OpenedFile file; + bool isFileReadOnly; + + public OpenedFile File { + get { return file; } + } public FileChangeWatcher(OpenedFile file) { @@ -70,6 +88,8 @@ namespace ICSharpCode.SharpDevelop file.FileNameChanged += file_FileNameChanged; activeWatchers.Add(this); SetWatcher(); + + isFileReadOnly = (System.IO.File.GetAttributes(this.file.FileName) & FileAttributes.ReadOnly) == FileAttributes.ReadOnly; } void file_FileNameChanged(object sender, EventArgs e) @@ -165,6 +185,14 @@ namespace ICSharpCode.SharpDevelop LoggingService.Debug("File " + file.FileName + " was changed externally: " + e.ChangeType); if (!wasChangedExternally) { wasChangedExternally = true; + OnFileChanged(EventArgs.Empty); + + // if the file was only made readonly, don't prevent reloading it from disk + bool readOnly = (System.IO.File.GetAttributes(this.file.FileName) & FileAttributes.ReadOnly) == FileAttributes.ReadOnly; + if (readOnly != isFileReadOnly) + wasChangedExternally = false; + isFileReadOnly = readOnly; + if (WorkbenchSingleton.Workbench.IsActiveWindow) { // delay reloading message a bit, prevents showing two messages // when the file changes twice in quick succession; and prevents @@ -174,8 +202,6 @@ namespace ICSharpCode.SharpDevelop delegate { MainForm_Activated(this, EventArgs.Empty); } ); } } - - file.RegisteredViewContents.ForEach(vc => vc.WorkbenchWindow.RefreshStatus()); } void MainForm_Activated(object sender, EventArgs e) @@ -187,14 +213,14 @@ namespace ICSharpCode.SharpDevelop return; string fileName = file.FileName; - if (!File.Exists(fileName)) + if (!System.IO.File.Exists(fileName)) return; string message = StringParser.Parse("${res:ICSharpCode.SharpDevelop.DefaultEditor.Gui.Editor.TextEditorDisplayBinding.FileAlteredMessage}", new string[,] {{"File", Path.GetFullPath(fileName)}}); if ((AutoLoadExternalChangesOption && file.IsDirty == false) || MessageService.AskQuestion(message, StringParser.Parse("${res:MainWindow.DialogName}"))) { - if (File.Exists(fileName)) { + if (System.IO.File.Exists(fileName)) { file.ReloadFromDisk(); } } else { diff --git a/src/Main/Base/Project/Src/Util/FakeXmlViewContent.cs b/src/Main/Base/Project/Src/Util/FakeXmlViewContent.cs index fa3d7f3250..46bfa4d3d3 100644 --- a/src/Main/Base/Project/Src/Util/FakeXmlViewContent.cs +++ b/src/Main/Base/Project/Src/Util/FakeXmlViewContent.cs @@ -213,5 +213,14 @@ namespace ICSharpCode.SharpDevelop.Util return null; } #endregion + + public event EventHandler IsReadOnlyChanged; + + protected void OnIsReadOnlyChanged(EventArgs e) + { + if (IsReadOnlyChanged != null) { + IsReadOnlyChanged(this, e); + } + } } }