diff --git a/src/AddIns/BackendBindings/WixBinding/Test/Utils/MockViewContent.cs b/src/AddIns/BackendBindings/WixBinding/Test/Utils/MockViewContent.cs index 6a1fd4190a..511b14dbc4 100644 --- a/src/AddIns/BackendBindings/WixBinding/Test/Utils/MockViewContent.cs +++ b/src/AddIns/BackendBindings/WixBinding/Test/Utils/MockViewContent.cs @@ -29,17 +29,39 @@ namespace WixBinding.Tests.Utils public void SetName(string fileName) { - primaryFile = OpenedFile.CreateDummyOpenedFile(fileName, false); + primaryFile = new MockOpenedFile(fileName, false); } public void SetUntitledName(string fileName) { - primaryFile = OpenedFile.CreateDummyOpenedFile(fileName, true); + primaryFile = new MockOpenedFile(fileName, true); + } + + class MockOpenedFile : OpenedFile + { + public MockOpenedFile(string fileName, bool isUntitled) + { + base.FileName = fileName; + base.IsUntitled = isUntitled; + } + + public override IList RegisteredViewContents { + get { + throw new NotImplementedException(); + } + } + + public override void RegisterView(IViewContent view) + { + } + + public override void UnregisterView(IViewContent view) + { + } } #pragma warning disable 67 public event EventHandler TabPageTextChanged; - public event EventHandler SwitchedTo; public event EventHandler Disposed; public event EventHandler IsDirtyChanged; public event EventHandler TitleNameChanged; @@ -144,11 +166,6 @@ namespace WixBinding.Tests.Utils } } - public void OnSwitchedTo() - { - throw new NotImplementedException(); - } - public void RedrawContent() { throw new NotImplementedException(); diff --git a/src/AddIns/DisplayBindings/FormsDesigner/Project/Src/DesignerViewContent.cs b/src/AddIns/DisplayBindings/FormsDesigner/Project/Src/DesignerViewContent.cs index 59e36e14d8..d19c2275ff 100644 --- a/src/AddIns/DisplayBindings/FormsDesigner/Project/Src/DesignerViewContent.cs +++ b/src/AddIns/DisplayBindings/FormsDesigner/Project/Src/DesignerViewContent.cs @@ -155,6 +155,7 @@ namespace ICSharpCode.FormsDesigner } UpdatePropertyPad(); + PropertyPad.PropertyValueChanged += PropertyValueChanged; hasUnmergedChanges = false; @@ -208,6 +209,7 @@ namespace ICSharpCode.FormsDesigner void UnloadDesigner() { + PropertyPad.PropertyValueChanged -= PropertyValueChanged; generator.Detach(); bool savedIsDirty = this.PrimaryFile.IsDirty; p.Controls.Clear(); @@ -579,6 +581,8 @@ namespace ICSharpCode.FormsDesigner { if (e.ChangedItem == null || e.OldValue == null) return; + if (!propertyContainer.IsActivePropertyContainer) + return; if (e.ChangedItem.GridItemType == GridItemType.Property) { if (e.ChangedItem.PropertyDescriptor.Name == "Language") { if (!e.OldValue.Equals(e.ChangedItem.Value)) { diff --git a/src/AddIns/DisplayBindings/XmlEditor/Test/Tree/XmlTreeViewClipboardHandlerTestFixture.cs b/src/AddIns/DisplayBindings/XmlEditor/Test/Tree/XmlTreeViewClipboardHandlerTestFixture.cs index 5d33521d9c..77ea7b3a32 100644 --- a/src/AddIns/DisplayBindings/XmlEditor/Test/Tree/XmlTreeViewClipboardHandlerTestFixture.cs +++ b/src/AddIns/DisplayBindings/XmlEditor/Test/Tree/XmlTreeViewClipboardHandlerTestFixture.cs @@ -35,16 +35,17 @@ namespace XmlEditor.Tests.Tree [SetUp] public void SetUp() { + MockOpenedFile openedFile = new MockOpenedFile("test.xml"); XmlSchemaCompletionDataCollection schemas = new XmlSchemaCompletionDataCollection(); xmlView = new XmlView(new DefaultTextEditorProperties(), schemas); - xmlView.SetPrimaryFileUnitTestMode(OpenedFile.CreateDummyOpenedFile("test.xml", true)); + xmlView.SetPrimaryFileUnitTestMode(openedFile); view = new XmlTreeView(xmlView, null, null); treeViewContainer = (XmlTreeViewContainerControl)view.Control; treeView = treeViewContainer.TreeView; clipboardHandler = view as IClipboardHandler; xmlView.XmlEditor.Text = "

"; - ((IViewContent)view).OnSwitchedTo(); + openedFile.SwitchToView(view); htmlTreeNode = treeView.Nodes[0] as XmlElementTreeNode; htmlTreeNode.PerformInitialization(); diff --git a/src/AddIns/DisplayBindings/XmlEditor/Test/Utils/MockOpenedFile.cs b/src/AddIns/DisplayBindings/XmlEditor/Test/Utils/MockOpenedFile.cs new file mode 100644 index 0000000000..dcc69900a1 --- /dev/null +++ b/src/AddIns/DisplayBindings/XmlEditor/Test/Utils/MockOpenedFile.cs @@ -0,0 +1,59 @@ +// +// +// +// +// $Revision: 2658$ +// + +using System; +using ICSharpCode.SharpDevelop.Gui; +using ICSharpCode.SharpDevelop; +using System.Collections.Generic; + +namespace XmlEditor.Tests.Utils +{ + /// + /// Description of MockOpenedFile. + /// + public class MockOpenedFile : OpenedFile + { + public MockOpenedFile(string fileName) + { + base.FileName = fileName; + base.IsUntitled = true; + SetData(new byte[0]); + } + + List registeredViews = new List(); + + public override IList RegisteredViewContents { + get { return registeredViews.AsReadOnly(); } + } + + public override void RegisterView(IViewContent view) + { + if (view == null) + throw new ArgumentNullException("view"); + if (registeredViews.Contains(view)) + throw new ArgumentException("registeredViews already contains view"); + + registeredViews.Add(view); + + if (registeredViews.Count == 1) + SwitchedToView(registeredViews[0]); + } + + public override void UnregisterView(IViewContent view) + { + if (!registeredViews.Remove(view)) + throw new ArgumentException("registeredViews does not contain view"); + } + + public void SwitchToView(IViewContent view) + { + if (!registeredViews.Contains(view)) + throw new ArgumentException("registeredViews does not contain view"); + base.SwitchedToView(view); + } + } +} diff --git a/src/AddIns/DisplayBindings/XmlEditor/Test/XmlEditor.Tests.csproj b/src/AddIns/DisplayBindings/XmlEditor/Test/XmlEditor.Tests.csproj index ad18bb17cb..63039e7ea1 100644 --- a/src/AddIns/DisplayBindings/XmlEditor/Test/XmlEditor.Tests.csproj +++ b/src/AddIns/DisplayBindings/XmlEditor/Test/XmlEditor.Tests.csproj @@ -94,6 +94,7 @@ + diff --git a/src/Main/Base/Project/ICSharpCode.SharpDevelop.csproj b/src/Main/Base/Project/ICSharpCode.SharpDevelop.csproj index c6cdf9efa0..76522ccbc5 100644 --- a/src/Main/Base/Project/ICSharpCode.SharpDevelop.csproj +++ b/src/Main/Base/Project/ICSharpCode.SharpDevelop.csproj @@ -102,6 +102,7 @@ + diff --git a/src/Main/Base/Project/Src/Gui/Dialogs/OptionPanels/IDEOptions/LoadSavePanel.cs b/src/Main/Base/Project/Src/Gui/Dialogs/OptionPanels/IDEOptions/LoadSavePanel.cs index af8538faa0..4a787b5dbe 100644 --- a/src/Main/Base/Project/Src/Gui/Dialogs/OptionPanels/IDEOptions/LoadSavePanel.cs +++ b/src/Main/Base/Project/Src/Gui/Dialogs/OptionPanels/IDEOptions/LoadSavePanel.cs @@ -8,7 +8,7 @@ using System; using System.Windows.Forms; using ICSharpCode.Core; -using FileChangeWatcher = ICSharpCode.SharpDevelop.OpenedFile.FileChangeWatcher; +using FileChangeWatcher = ICSharpCode.SharpDevelop.FileChangeWatcher; namespace ICSharpCode.SharpDevelop.Gui.OptionPanels { diff --git a/src/Main/Base/Project/Src/Gui/Pads/PropertyPad/PropertyContainer.cs b/src/Main/Base/Project/Src/Gui/Pads/PropertyPad/PropertyContainer.cs index 02b538d925..4002df235a 100644 --- a/src/Main/Base/Project/Src/Gui/Pads/PropertyPad/PropertyContainer.cs +++ b/src/Main/Base/Project/Src/Gui/Pads/PropertyPad/PropertyContainer.cs @@ -49,6 +49,13 @@ namespace ICSharpCode.SharpDevelop.Gui } } + /// + /// Gets if this property container is currently shown in the property grid. + /// + public bool IsActivePropertyContainer { + get { return PropertyPad.ActiveContainer == this; } + } + object selectedObject; object[] selectedObjects; diff --git a/src/Main/Base/Project/Src/Gui/Pads/PropertyPad/PropertyPad.cs b/src/Main/Base/Project/Src/Gui/Pads/PropertyPad/PropertyPad.cs index 2b1f0563d3..040ba160c6 100644 --- a/src/Main/Base/Project/Src/Gui/Pads/PropertyPad/PropertyPad.cs +++ b/src/Main/Base/Project/Src/Gui/Pads/PropertyPad/PropertyPad.cs @@ -26,6 +26,10 @@ namespace ICSharpCode.SharpDevelop.Gui PropertyContainer activeContainer; + internal static PropertyContainer ActiveContainer { + get { return instance.activeContainer; } + } + void SetActiveContainer(PropertyContainer pc) { if (activeContainer == pc) diff --git a/src/Main/Base/Project/Src/Gui/WorkbenchSingleton.cs b/src/Main/Base/Project/Src/Gui/WorkbenchSingleton.cs index 28e83513e6..815ede51f6 100644 --- a/src/Main/Base/Project/Src/Gui/WorkbenchSingleton.cs +++ b/src/Main/Base/Project/Src/Gui/WorkbenchSingleton.cs @@ -21,9 +21,12 @@ namespace ICSharpCode.SharpDevelop.Gui static STAThreadCaller caller; static DefaultWorkbench workbench; + /// + /// Gets the main form. Returns null in unit-testing mode. + /// public static Form MainForm { get { - return (Form)workbench; + return workbench as Form; } } diff --git a/src/Main/Base/Project/Src/Services/File/FileChangeWatcher.cs b/src/Main/Base/Project/Src/Services/File/FileChangeWatcher.cs new file mode 100644 index 0000000000..4193118e41 --- /dev/null +++ b/src/Main/Base/Project/Src/Services/File/FileChangeWatcher.cs @@ -0,0 +1,126 @@ +// +// +// +// +// $Revision$ +// + +using System; +using System.Collections.Generic; +using System.Diagnostics; +using System.IO; +using ICSharpCode.SharpDevelop.Gui; +using ICSharpCode.Core; + +namespace ICSharpCode.SharpDevelop +{ + #region FileChangeWatcher + internal sealed class FileChangeWatcher //: IDisposable + { + /*FileSystemWatcher watcher; + bool wasChangedExternally = false; + string fileName; + AbstractViewContent viewContent; + + public FileChangeWatcher(AbstractViewContent viewContent) + { + this.viewContent = viewContent; + WorkbenchSingleton.MainForm.Activated += GotFocusEvent; + } + */ + + public static bool DetectExternalChangesOption { + get { + return PropertyService.Get("SharpDevelop.FileChangeWatcher.DetectExternalChanges", true); + } + set { + PropertyService.Set("SharpDevelop.FileChangeWatcher.DetectExternalChanges", value); + } + } + + public static bool AutoLoadExternalChangesOption { + get { + return PropertyService.Get("SharpDevelop.FileChangeWatcher.AutoLoadExternalChanges", true); + } + set { + PropertyService.Set("SharpDevelop.FileChangeWatcher.AutoLoadExternalChanges", value); + } + } + + /* + public void Dispose() + { + WorkbenchSingleton.MainForm.Activated -= GotFocusEvent; + if (watcher != null) { + watcher.Dispose(); + } + } + + public void Disable() + { + if (watcher != null) { + watcher.EnableRaisingEvents = false; + } + } + + public void SetWatcher(string fileName) + { + this.fileName = fileName; + if (DetectExternalChangesOption == false) + return; + try { + if (this.watcher == null) { + this.watcher = new FileSystemWatcher(); + this.watcher.SynchronizingObject = WorkbenchSingleton.MainForm; + this.watcher.Changed += new FileSystemEventHandler(this.OnFileChangedEvent); + } else { + this.watcher.EnableRaisingEvents = false; + } + this.watcher.Path = Path.GetDirectoryName(fileName); + this.watcher.Filter = Path.GetFileName(fileName); + this.watcher.NotifyFilter = NotifyFilters.LastWrite; + this.watcher.EnableRaisingEvents = true; + } catch (PlatformNotSupportedException) { + if (watcher != null) { + watcher.Dispose(); + } + watcher = null; + } + } + + void OnFileChangedEvent(object sender, FileSystemEventArgs e) + { + if (e.ChangeType != WatcherChangeTypes.Deleted) { + wasChangedExternally = true; + if (ICSharpCode.SharpDevelop.Gui.WorkbenchSingleton.Workbench.IsActiveWindow) { + // delay showing message a bit, prevents showing two messages + // when the file changes twice in quick succession + WorkbenchSingleton.SafeThreadAsyncCall(GotFocusEvent, this, EventArgs.Empty); + } + } + } + + void GotFocusEvent(object sender, EventArgs e) + { + if (wasChangedExternally) { + wasChangedExternally = false; + + string message = StringParser.Parse("${res:ICSharpCode.SharpDevelop.DefaultEditor.Gui.Editor.TextEditorDisplayBinding.FileAlteredMessage}", new string[,] {{"File", Path.GetFullPath(fileName)}}); + if ((AutoLoadExternalChangesOption && viewContent.IsDirty == false) + || MessageBox.Show(message, + StringParser.Parse("${res:MainWindow.DialogName}"), + MessageBoxButtons.YesNo, + MessageBoxIcon.Question) == DialogResult.Yes) + { + if (File.Exists(fileName)) { + viewContent.Load(fileName); + } + } else { + viewContent.IsDirty = true; + } + } + } + */ + } + #endregion +} diff --git a/src/Main/Base/Project/Src/Services/File/FileService.cs b/src/Main/Base/Project/Src/Services/File/FileService.cs index b964fb669c..611b35d88e 100644 --- a/src/Main/Base/Project/Src/Services/File/FileService.cs +++ b/src/Main/Base/Project/Src/Services/File/FileService.cs @@ -99,7 +99,7 @@ namespace ICSharpCode.SharpDevelop fileName = FileUtility.NormalizePath(fileName); OpenedFile file; if (!openedFileDict.TryGetValue(fileName, out file)) { - openedFileDict[fileName] = file = new OpenedFile(fileName); + openedFileDict[fileName] = file = new FileServiceOpenedFile(fileName); } return file; } @@ -112,7 +112,7 @@ namespace ICSharpCode.SharpDevelop if (defaultName == null) throw new ArgumentNullException("defaultName"); - OpenedFile file = new OpenedFile(content); + OpenedFile file = new FileServiceOpenedFile(content); file.FileName = file.GetHashCode() + "/" + defaultName; openedFileDict[file.FileName] = file; return file; diff --git a/src/Main/Base/Project/Src/Services/File/OpenedFile.cs b/src/Main/Base/Project/Src/Services/File/OpenedFile.cs index fe6bcc4dee..9d7972c466 100644 --- a/src/Main/Base/Project/Src/Services/File/OpenedFile.cs +++ b/src/Main/Base/Project/Src/Services/File/OpenedFile.cs @@ -17,14 +17,11 @@ namespace ICSharpCode.SharpDevelop /// /// Represents an opened file. /// - public sealed class OpenedFile : ICanBeDirty + public abstract class OpenedFile : ICanBeDirty { - bool isConnectedWithFileService = true; - string fileName; - - IViewContent currentView; - bool isUntitled; - List registeredViews = new List(); + protected IViewContent currentView; + bool inLoadOperation; + bool inSaveOperation; /// /// holds unsaved file content in memory when view containing the file was closed but no other view @@ -32,41 +29,52 @@ namespace ICSharpCode.SharpDevelop /// byte[] fileData; - internal OpenedFile(string fileName) - { - this.fileName = fileName; - isUntitled = false; - } + #region IsDirty + bool isDirty; + public event EventHandler IsDirtyChanged; - internal OpenedFile(byte[] fileData) - { - this.fileName = null; - this.fileData = fileData; - isUntitled = true; - MakeDirty(); + /// + /// Gets/sets if the file is has unsaved changes. + /// + public bool IsDirty { + get { return isDirty;} + set { + if (isDirty != value) { + isDirty = value; + + if (IsDirtyChanged != null) { + IsDirtyChanged(this, EventArgs.Empty); + } + } + } } /// - /// Creates a dummy opened file instance. Use for unit tests only! + /// Marks the file as dirty if it currently is not in a load operation. /// - public static OpenedFile CreateDummyOpenedFile(string name, bool isUntitled) + public virtual void MakeDirty() { - if (isUntitled) { - OpenedFile f = new OpenedFile(new byte[0]); - f.isConnectedWithFileService = false; - f.FileName = name; - return f; - } else { - OpenedFile f = new OpenedFile(name); - f.isConnectedWithFileService = false; - return f; + if (!inLoadOperation) { + this.IsDirty = true; } } + #endregion + bool isUntitled; + + /// + /// Gets if the file is untitled. Untitled files show a "Save as" dialog when they are saved. + /// public bool IsUntitled { get { return isUntitled; } + protected set { isUntitled = value; } } + string fileName; + + /// + /// Gets the name of the file. + /// public string FileName { get { return fileName; } set { @@ -75,25 +83,71 @@ namespace ICSharpCode.SharpDevelop value = FileUtility.NormalizePath(value); if (fileName != value) { - if (isConnectedWithFileService) { - FileService.OpenedFileFileNameChange(this, fileName, value); - } - fileName = value; - - if (FileNameChanged != null) { - FileNameChanged(this, EventArgs.Empty); - } + ChangeFileName(value); } } } + protected virtual void ChangeFileName(string newValue) + { + fileName = newValue; + + if (FileNameChanged != null) { + FileNameChanged(this, EventArgs.Empty); + } + } + + /// + /// Occurs when the file name has changed. + /// public event EventHandler FileNameChanged; + /// + /// Use this method to save the file to disk using a new name. + /// + public void SaveToDisk(string newFileName) + { + this.FileName = newFileName; + this.IsUntitled = false; + SaveToDisk(); + } + + public abstract void RegisterView(IViewContent view); + public abstract void UnregisterView(IViewContent view); + + public virtual void CloseIfAllViewsClosed() + { + } + + /// + /// Forces initialization of the specified view. + /// + public virtual void ForceInitializeView(IViewContent view) + { + if (view == null) + throw new ArgumentNullException("view"); + + if (currentView != view) { + if (currentView == null) { + SwitchedToView(view); + } else { + try { + inLoadOperation = true; + using (Stream sourceStream = OpenRead()) { + view.Load(this, sourceStream); + } + } finally { + inLoadOperation = false; + } + } + } + } + /// /// Gets the list of view contents registered with this opened file. /// - public IList RegisteredViewContents { - get { return registeredViews.AsReadOnly(); } + public abstract IList RegisteredViewContents { + get; } /// @@ -110,12 +164,12 @@ namespace ICSharpCode.SharpDevelop /// /// Opens the file for reading. /// - public Stream OpenRead() + public virtual Stream OpenRead() { if (fileData != null) { return new MemoryStream(fileData, false); } else { - return new FileStream(fileName, FileMode.Open, FileAccess.Read); + return new FileStream(FileName, FileMode.Open, FileAccess.Read); } } @@ -129,7 +183,7 @@ namespace ICSharpCode.SharpDevelop /// for a file that doesn't exist on disk but should be automatically created when a view /// with the file is saved, e.g. for .resx files created by the forms designer. /// - public void SetData(byte[] fileData) + public virtual void SetData(byte[] fileData) { if (fileData == null) throw new ArgumentNullException("fileData"); @@ -141,16 +195,12 @@ namespace ICSharpCode.SharpDevelop this.fileData = fileData; } - public void SaveToDisk(string newFileName) - { - this.FileName = newFileName; - isUntitled = false; - SaveToDisk(); - } - - public void SaveToDisk() + /// + /// Save the file to disk using the current name. + /// + public virtual void SaveToDisk() { - if (isUntitled) + if (IsUntitled) throw new InvalidOperationException("Cannot save an untitled file to disk!"); /* @@ -167,7 +217,7 @@ namespace ICSharpCode.SharpDevelop } } */ - using (FileStream fs = new FileStream(fileName, FileMode.Create, FileAccess.Write)) { + using (FileStream fs = new FileStream(FileName, FileMode.Create, FileAccess.Write)) { if (currentView != null) { SaveCurrentViewToStream(fs); } else { @@ -187,7 +237,6 @@ namespace ICSharpCode.SharpDevelop // /// // public event EventHandler SavedCurrentView; - bool inSaveOperation; void SaveCurrentViewToStream(Stream stream) { @@ -203,7 +252,7 @@ namespace ICSharpCode.SharpDevelop // SavedCurrentView(this, EventArgs.Empty); } - void SaveCurrentView() + protected void SaveCurrentView() { using (MemoryStream memoryStream = new MemoryStream()) { SaveCurrentViewToStream(memoryStream); @@ -211,100 +260,8 @@ namespace ICSharpCode.SharpDevelop } } - public void RegisterView(IViewContent view) - { - if (view == null) - throw new ArgumentNullException("view"); - Debug.Assert(!registeredViews.Contains(view)); - - registeredViews.Add(view); - - WorkbenchSingleton.Workbench.ActiveViewContentChanged += WorkbenchActiveViewContentChanged; - if (WorkbenchSingleton.Workbench.ActiveViewContent == view) { - SwitchedToView(view); - } - #if DEBUG - view.Disposed += ViewDisposed; - #endif - } - - public void UnregisterView(IViewContent view) - { - if (view == null) - throw new ArgumentNullException("view"); - Debug.Assert(registeredViews.Contains(view)); - - WorkbenchSingleton.Workbench.ActiveViewContentChanged -= WorkbenchActiveViewContentChanged; - #if DEBUG - view.Disposed -= ViewDisposed; - #endif - - registeredViews.Remove(view); - if (registeredViews.Count > 0) { - if (currentView == view) { - SaveCurrentView(); - currentView = null; - } - } else { - // all views to the file were closed - if (isConnectedWithFileService) { - FileService.OpenedFileClosed(this); - } - } - } - - internal void CloseIfAllViewsClosed() - { - if (registeredViews.Count == 0) { - if (isConnectedWithFileService) { - FileService.OpenedFileClosed(this); - } - } - } - - #if DEBUG - void ViewDisposed(object sender, EventArgs e) - { - Debug.Fail("View was disposed while still registered with OpenedFile!"); - } - #endif - - /// - /// Forces initialization of the specified view. - /// - public void ForceInitializeView(IViewContent view) - { - if (view == null) - throw new ArgumentNullException("view"); - Debug.Assert(registeredViews.Contains(view)); - - if (currentView != view) { - if (currentView == null) { - SwitchedToView(view); - } else { - try { - inLoadOperation = true; - using (Stream sourceStream = OpenRead()) { - view.Load(this, sourceStream); - } - } finally { - inLoadOperation = false; - } - } - } - } - - void WorkbenchActiveViewContentChanged(object sender, EventArgs e) - { - IViewContent newView = WorkbenchSingleton.Workbench.ActiveViewContent; - - if (!registeredViews.Contains(newView)) - return; - - SwitchedToView(newView); - } - void SwitchedToView(IViewContent newView) + protected void SwitchedToView(IViewContent newView) { if (currentView != null) { if (newView.SupportsSwitchToThisWithoutSaveLoad(this, currentView) @@ -333,7 +290,7 @@ namespace ICSharpCode.SharpDevelop } } - public void ReloadFromDisk() + public virtual void ReloadFromDisk() { fileData = null; if (currentView != null) { @@ -347,157 +304,116 @@ namespace ICSharpCode.SharpDevelop } } } + } + + sealed class FileServiceOpenedFile : OpenedFile + { + List registeredViews = new List(); - /* - internal void ChangeView(IViewContent newView) + protected override void ChangeFileName(string newValue) { - if (currentView != null && currentView != newView) { - SaveCurrentView(); - } - using (Stream sourceStream = OpenRead()) { - currentView = newView; - fileData = null; - newView.Load(this, sourceStream); - } + FileService.OpenedFileFileNameChange(this, this.FileName, newValue); + base.ChangeFileName(newValue); } - */ - - bool isDirty; - public event EventHandler IsDirtyChanged; - public bool IsDirty { - get { return isDirty;} - set { - if (isDirty != value) { - isDirty = value; - - if (IsDirtyChanged != null) { - IsDirtyChanged(this, EventArgs.Empty); - } - } - } + internal FileServiceOpenedFile(string fileName) + { + this.FileName = fileName; + IsUntitled = false; } - bool inLoadOperation; + internal FileServiceOpenedFile(byte[] fileData) + { + this.FileName = null; + SetData(fileData); + IsUntitled = true; + MakeDirty(); + } /// - /// Marks the file as dirty if it currently is not in a load operation. + /// Gets the list of view contents registered with this opened file. /// - public void MakeDirty() - { - if (!inLoadOperation) { - this.IsDirty = true; - } + public override IList RegisteredViewContents { + get { return registeredViews.AsReadOnly(); } } - #region FileChangeWatcher - internal sealed class FileChangeWatcher //: IDisposable + public override void ForceInitializeView(IViewContent view) { - /*FileSystemWatcher watcher; - bool wasChangedExternally = false; - string fileName; - AbstractViewContent viewContent; + if (view == null) + throw new ArgumentNullException("view"); + if (!registeredViews.Contains(view)) + throw new ArgumentException("registeredViews must contain view"); - public FileChangeWatcher(AbstractViewContent viewContent) - { - this.viewContent = viewContent; - WorkbenchSingleton.MainForm.Activated += GotFocusEvent; - } - */ + base.ForceInitializeView(view); + } + + public override void RegisterView(IViewContent view) + { + if (view == null) + throw new ArgumentNullException("view"); + if (registeredViews.Contains(view)) + throw new ArgumentException("registeredViews already contains view"); - public static bool DetectExternalChangesOption { - get { - return PropertyService.Get("SharpDevelop.FileChangeWatcher.DetectExternalChanges", true); - } - set { - PropertyService.Set("SharpDevelop.FileChangeWatcher.DetectExternalChanges", value); - } - } + registeredViews.Add(view); - public static bool AutoLoadExternalChangesOption { - get { - return PropertyService.Get("SharpDevelop.FileChangeWatcher.AutoLoadExternalChanges", true); - } - set { - PropertyService.Set("SharpDevelop.FileChangeWatcher.AutoLoadExternalChanges", value); + if (WorkbenchSingleton.Workbench != null) { + WorkbenchSingleton.Workbench.ActiveViewContentChanged += WorkbenchActiveViewContentChanged; + if (WorkbenchSingleton.Workbench.ActiveViewContent == view) { + SwitchedToView(view); } } + #if DEBUG + view.Disposed += ViewDisposed; + #endif + } + + public override void UnregisterView(IViewContent view) + { + if (view == null) + throw new ArgumentNullException("view"); + Debug.Assert(registeredViews.Contains(view)); - /* - public void Dispose() - { - WorkbenchSingleton.MainForm.Activated -= GotFocusEvent; - if (watcher != null) { - watcher.Dispose(); - } + if (WorkbenchSingleton.Workbench != null) { + WorkbenchSingleton.Workbench.ActiveViewContentChanged -= WorkbenchActiveViewContentChanged; } + #if DEBUG + view.Disposed -= ViewDisposed; + #endif - public void Disable() - { - if (watcher != null) { - watcher.EnableRaisingEvents = false; + registeredViews.Remove(view); + if (registeredViews.Count > 0) { + if (currentView == view) { + SaveCurrentView(); + currentView = null; } + } else { + // all views to the file were closed + FileService.OpenedFileClosed(this); } - - public void SetWatcher(string fileName) - { - this.fileName = fileName; - if (DetectExternalChangesOption == false) - return; - try { - if (this.watcher == null) { - this.watcher = new FileSystemWatcher(); - this.watcher.SynchronizingObject = WorkbenchSingleton.MainForm; - this.watcher.Changed += new FileSystemEventHandler(this.OnFileChangedEvent); - } else { - this.watcher.EnableRaisingEvents = false; - } - this.watcher.Path = Path.GetDirectoryName(fileName); - this.watcher.Filter = Path.GetFileName(fileName); - this.watcher.NotifyFilter = NotifyFilters.LastWrite; - this.watcher.EnableRaisingEvents = true; - } catch (PlatformNotSupportedException) { - if (watcher != null) { - watcher.Dispose(); - } - watcher = null; - } + } + + public override void CloseIfAllViewsClosed() + { + if (registeredViews.Count == 0) { + FileService.OpenedFileClosed(this); } + } + + #if DEBUG + void ViewDisposed(object sender, EventArgs e) + { + Debug.Fail("View was disposed while still registered with OpenedFile!"); + } + #endif + + void WorkbenchActiveViewContentChanged(object sender, EventArgs e) + { + IViewContent newView = WorkbenchSingleton.Workbench.ActiveViewContent; - void OnFileChangedEvent(object sender, FileSystemEventArgs e) - { - if (e.ChangeType != WatcherChangeTypes.Deleted) { - wasChangedExternally = true; - if (ICSharpCode.SharpDevelop.Gui.WorkbenchSingleton.Workbench.IsActiveWindow) { - // delay showing message a bit, prevents showing two messages - // when the file changes twice in quick succession - WorkbenchSingleton.SafeThreadAsyncCall(GotFocusEvent, this, EventArgs.Empty); - } - } - } + if (!registeredViews.Contains(newView)) + return; - void GotFocusEvent(object sender, EventArgs e) - { - if (wasChangedExternally) { - wasChangedExternally = false; - - string message = StringParser.Parse("${res:ICSharpCode.SharpDevelop.DefaultEditor.Gui.Editor.TextEditorDisplayBinding.FileAlteredMessage}", new string[,] {{"File", Path.GetFullPath(fileName)}}); - if ((AutoLoadExternalChangesOption && viewContent.IsDirty == false) - || MessageBox.Show(message, - StringParser.Parse("${res:MainWindow.DialogName}"), - MessageBoxButtons.YesNo, - MessageBoxIcon.Question) == DialogResult.Yes) - { - if (File.Exists(fileName)) { - viewContent.Load(fileName); - } - } else { - viewContent.IsDirty = true; - } - } - } - */ + SwitchedToView(newView); } - #endregion } }