Browse Source

Fixed build.

Allow unit testing of view contents by decoupling OpenedFile from FileService and Workbench.

git-svn-id: svn://svn.sharpdevelop.net/sharpdevelop/trunk@2663 1ccf3a8d-04fe-1044-b7c0-cef0b8235c61
shortcuts
Daniel Grunwald 19 years ago
parent
commit
0333757269
  1. 33
      src/AddIns/BackendBindings/WixBinding/Test/Utils/MockViewContent.cs
  2. 4
      src/AddIns/DisplayBindings/FormsDesigner/Project/Src/DesignerViewContent.cs
  3. 5
      src/AddIns/DisplayBindings/XmlEditor/Test/Tree/XmlTreeViewClipboardHandlerTestFixture.cs
  4. 59
      src/AddIns/DisplayBindings/XmlEditor/Test/Utils/MockOpenedFile.cs
  5. 1
      src/AddIns/DisplayBindings/XmlEditor/Test/XmlEditor.Tests.csproj
  6. 1
      src/Main/Base/Project/ICSharpCode.SharpDevelop.csproj
  7. 2
      src/Main/Base/Project/Src/Gui/Dialogs/OptionPanels/IDEOptions/LoadSavePanel.cs
  8. 7
      src/Main/Base/Project/Src/Gui/Pads/PropertyPad/PropertyContainer.cs
  9. 4
      src/Main/Base/Project/Src/Gui/Pads/PropertyPad/PropertyPad.cs
  10. 5
      src/Main/Base/Project/Src/Gui/WorkbenchSingleton.cs
  11. 126
      src/Main/Base/Project/Src/Services/File/FileChangeWatcher.cs
  12. 4
      src/Main/Base/Project/Src/Services/File/FileService.cs
  13. 462
      src/Main/Base/Project/Src/Services/File/OpenedFile.cs

33
src/AddIns/BackendBindings/WixBinding/Test/Utils/MockViewContent.cs

@ -29,17 +29,39 @@ namespace WixBinding.Tests.Utils
public void SetName(string fileName) public void SetName(string fileName)
{ {
primaryFile = OpenedFile.CreateDummyOpenedFile(fileName, false); primaryFile = new MockOpenedFile(fileName, false);
} }
public void SetUntitledName(string fileName) 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<IViewContent> RegisteredViewContents {
get {
throw new NotImplementedException();
}
}
public override void RegisterView(IViewContent view)
{
}
public override void UnregisterView(IViewContent view)
{
}
} }
#pragma warning disable 67 #pragma warning disable 67
public event EventHandler TabPageTextChanged; public event EventHandler TabPageTextChanged;
public event EventHandler SwitchedTo;
public event EventHandler Disposed; public event EventHandler Disposed;
public event EventHandler IsDirtyChanged; public event EventHandler IsDirtyChanged;
public event EventHandler TitleNameChanged; public event EventHandler TitleNameChanged;
@ -144,11 +166,6 @@ namespace WixBinding.Tests.Utils
} }
} }
public void OnSwitchedTo()
{
throw new NotImplementedException();
}
public void RedrawContent() public void RedrawContent()
{ {
throw new NotImplementedException(); throw new NotImplementedException();

4
src/AddIns/DisplayBindings/FormsDesigner/Project/Src/DesignerViewContent.cs

@ -155,6 +155,7 @@ namespace ICSharpCode.FormsDesigner
} }
UpdatePropertyPad(); UpdatePropertyPad();
PropertyPad.PropertyValueChanged += PropertyValueChanged;
hasUnmergedChanges = false; hasUnmergedChanges = false;
@ -208,6 +209,7 @@ namespace ICSharpCode.FormsDesigner
void UnloadDesigner() void UnloadDesigner()
{ {
PropertyPad.PropertyValueChanged -= PropertyValueChanged;
generator.Detach(); generator.Detach();
bool savedIsDirty = this.PrimaryFile.IsDirty; bool savedIsDirty = this.PrimaryFile.IsDirty;
p.Controls.Clear(); p.Controls.Clear();
@ -579,6 +581,8 @@ namespace ICSharpCode.FormsDesigner
{ {
if (e.ChangedItem == null || e.OldValue == null) if (e.ChangedItem == null || e.OldValue == null)
return; return;
if (!propertyContainer.IsActivePropertyContainer)
return;
if (e.ChangedItem.GridItemType == GridItemType.Property) { if (e.ChangedItem.GridItemType == GridItemType.Property) {
if (e.ChangedItem.PropertyDescriptor.Name == "Language") { if (e.ChangedItem.PropertyDescriptor.Name == "Language") {
if (!e.OldValue.Equals(e.ChangedItem.Value)) { if (!e.OldValue.Equals(e.ChangedItem.Value)) {

5
src/AddIns/DisplayBindings/XmlEditor/Test/Tree/XmlTreeViewClipboardHandlerTestFixture.cs

@ -35,16 +35,17 @@ namespace XmlEditor.Tests.Tree
[SetUp] [SetUp]
public void SetUp() public void SetUp()
{ {
MockOpenedFile openedFile = new MockOpenedFile("test.xml");
XmlSchemaCompletionDataCollection schemas = new XmlSchemaCompletionDataCollection(); XmlSchemaCompletionDataCollection schemas = new XmlSchemaCompletionDataCollection();
xmlView = new XmlView(new DefaultTextEditorProperties(), schemas); xmlView = new XmlView(new DefaultTextEditorProperties(), schemas);
xmlView.SetPrimaryFileUnitTestMode(OpenedFile.CreateDummyOpenedFile("test.xml", true)); xmlView.SetPrimaryFileUnitTestMode(openedFile);
view = new XmlTreeView(xmlView, null, null); view = new XmlTreeView(xmlView, null, null);
treeViewContainer = (XmlTreeViewContainerControl)view.Control; treeViewContainer = (XmlTreeViewContainerControl)view.Control;
treeView = treeViewContainer.TreeView; treeView = treeViewContainer.TreeView;
clipboardHandler = view as IClipboardHandler; clipboardHandler = view as IClipboardHandler;
xmlView.XmlEditor.Text = "<html><body><p></p></body></html>"; xmlView.XmlEditor.Text = "<html><body><p></p></body></html>";
((IViewContent)view).OnSwitchedTo(); openedFile.SwitchToView(view);
htmlTreeNode = treeView.Nodes[0] as XmlElementTreeNode; htmlTreeNode = treeView.Nodes[0] as XmlElementTreeNode;
htmlTreeNode.PerformInitialization(); htmlTreeNode.PerformInitialization();

59
src/AddIns/DisplayBindings/XmlEditor/Test/Utils/MockOpenedFile.cs

@ -0,0 +1,59 @@
// <file>
// <copyright see="prj:///doc/copyright.txt"/>
// <license see="prj:///doc/license.txt"/>
// <owner name="Daniel Grunwald" email="daniel@danielgrunwald.de"/>
// <version>$Revision: 2658$</version>
// </file>
using System;
using ICSharpCode.SharpDevelop.Gui;
using ICSharpCode.SharpDevelop;
using System.Collections.Generic;
namespace XmlEditor.Tests.Utils
{
/// <summary>
/// Description of MockOpenedFile.
/// </summary>
public class MockOpenedFile : OpenedFile
{
public MockOpenedFile(string fileName)
{
base.FileName = fileName;
base.IsUntitled = true;
SetData(new byte[0]);
}
List<IViewContent> registeredViews = new List<IViewContent>();
public override IList<IViewContent> 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);
}
}
}

1
src/AddIns/DisplayBindings/XmlEditor/Test/XmlEditor.Tests.csproj

@ -94,6 +94,7 @@
<Compile Include="Utils\DerivedXmlTreeView.cs" /> <Compile Include="Utils\DerivedXmlTreeView.cs" />
<Compile Include="Utils\DerivedXmlTreeViewContainerControl.cs" /> <Compile Include="Utils\DerivedXmlTreeViewContainerControl.cs" />
<Compile Include="Utils\MockAddXmlNodeDialog.cs" /> <Compile Include="Utils\MockAddXmlNodeDialog.cs" />
<Compile Include="Utils\MockOpenedFile.cs" />
<Compile Include="Utils\ResourceManager.cs" /> <Compile Include="Utils\ResourceManager.cs" />
<Compile Include="Schema\XhtmlStrictSchemaTestFixture.cs" /> <Compile Include="Schema\XhtmlStrictSchemaTestFixture.cs" />
<Compile Include="Schema\XsdSchemaTestFixture.cs" /> <Compile Include="Schema\XsdSchemaTestFixture.cs" />

1
src/Main/Base/Project/ICSharpCode.SharpDevelop.csproj

@ -102,6 +102,7 @@
<Compile Include="Src\Services\DisplayBinding\ExternalProcessDisplayBinding.cs" /> <Compile Include="Src\Services\DisplayBinding\ExternalProcessDisplayBinding.cs" />
<Compile Include="Src\Services\DisplayBinding\ISecondaryDisplayBinding.cs" /> <Compile Include="Src\Services\DisplayBinding\ISecondaryDisplayBinding.cs" />
<Compile Include="Src\Services\DisplayBinding\ShellExecuteDisplayBinding.cs" /> <Compile Include="Src\Services\DisplayBinding\ShellExecuteDisplayBinding.cs" />
<Compile Include="Src\Services\File\FileChangeWatcher.cs" />
<Compile Include="Src\Services\File\OpenedFile.cs" /> <Compile Include="Src\Services\File\OpenedFile.cs" />
<Compile Include="Src\Services\File\RecentOpen.cs" /> <Compile Include="Src\Services\File\RecentOpen.cs" />
<Compile Include="Src\Services\Language\LanguageService.cs" /> <Compile Include="Src\Services\Language\LanguageService.cs" />

2
src/Main/Base/Project/Src/Gui/Dialogs/OptionPanels/IDEOptions/LoadSavePanel.cs

@ -8,7 +8,7 @@
using System; using System;
using System.Windows.Forms; using System.Windows.Forms;
using ICSharpCode.Core; using ICSharpCode.Core;
using FileChangeWatcher = ICSharpCode.SharpDevelop.OpenedFile.FileChangeWatcher; using FileChangeWatcher = ICSharpCode.SharpDevelop.FileChangeWatcher;
namespace ICSharpCode.SharpDevelop.Gui.OptionPanels namespace ICSharpCode.SharpDevelop.Gui.OptionPanels
{ {

7
src/Main/Base/Project/Src/Gui/Pads/PropertyPad/PropertyContainer.cs

@ -49,6 +49,13 @@ namespace ICSharpCode.SharpDevelop.Gui
} }
} }
/// <summary>
/// Gets if this property container is currently shown in the property grid.
/// </summary>
public bool IsActivePropertyContainer {
get { return PropertyPad.ActiveContainer == this; }
}
object selectedObject; object selectedObject;
object[] selectedObjects; object[] selectedObjects;

4
src/Main/Base/Project/Src/Gui/Pads/PropertyPad/PropertyPad.cs

@ -26,6 +26,10 @@ namespace ICSharpCode.SharpDevelop.Gui
PropertyContainer activeContainer; PropertyContainer activeContainer;
internal static PropertyContainer ActiveContainer {
get { return instance.activeContainer; }
}
void SetActiveContainer(PropertyContainer pc) void SetActiveContainer(PropertyContainer pc)
{ {
if (activeContainer == pc) if (activeContainer == pc)

5
src/Main/Base/Project/Src/Gui/WorkbenchSingleton.cs

@ -21,9 +21,12 @@ namespace ICSharpCode.SharpDevelop.Gui
static STAThreadCaller caller; static STAThreadCaller caller;
static DefaultWorkbench workbench; static DefaultWorkbench workbench;
/// <summary>
/// Gets the main form. Returns null in unit-testing mode.
/// </summary>
public static Form MainForm { public static Form MainForm {
get { get {
return (Form)workbench; return workbench as Form;
} }
} }

126
src/Main/Base/Project/Src/Services/File/FileChangeWatcher.cs

@ -0,0 +1,126 @@
// <file>
// <copyright see="prj:///doc/copyright.txt"/>
// <license see="prj:///doc/license.txt"/>
// <owner name="Daniel Grunwald" email="daniel@danielgrunwald.de"/>
// <version>$Revision$</version>
// </file>
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
}

4
src/Main/Base/Project/Src/Services/File/FileService.cs

@ -99,7 +99,7 @@ namespace ICSharpCode.SharpDevelop
fileName = FileUtility.NormalizePath(fileName); fileName = FileUtility.NormalizePath(fileName);
OpenedFile file; OpenedFile file;
if (!openedFileDict.TryGetValue(fileName, out file)) { if (!openedFileDict.TryGetValue(fileName, out file)) {
openedFileDict[fileName] = file = new OpenedFile(fileName); openedFileDict[fileName] = file = new FileServiceOpenedFile(fileName);
} }
return file; return file;
} }
@ -112,7 +112,7 @@ namespace ICSharpCode.SharpDevelop
if (defaultName == null) if (defaultName == null)
throw new ArgumentNullException("defaultName"); throw new ArgumentNullException("defaultName");
OpenedFile file = new OpenedFile(content); OpenedFile file = new FileServiceOpenedFile(content);
file.FileName = file.GetHashCode() + "/" + defaultName; file.FileName = file.GetHashCode() + "/" + defaultName;
openedFileDict[file.FileName] = file; openedFileDict[file.FileName] = file;
return file; return file;

462
src/Main/Base/Project/Src/Services/File/OpenedFile.cs

@ -17,14 +17,11 @@ namespace ICSharpCode.SharpDevelop
/// <summary> /// <summary>
/// Represents an opened file. /// Represents an opened file.
/// </summary> /// </summary>
public sealed class OpenedFile : ICanBeDirty public abstract class OpenedFile : ICanBeDirty
{ {
bool isConnectedWithFileService = true; protected IViewContent currentView;
string fileName; bool inLoadOperation;
bool inSaveOperation;
IViewContent currentView;
bool isUntitled;
List<IViewContent> registeredViews = new List<IViewContent>();
/// <summary> /// <summary>
/// holds unsaved file content in memory when view containing the file was closed but no other view /// holds unsaved file content in memory when view containing the file was closed but no other view
@ -32,41 +29,52 @@ namespace ICSharpCode.SharpDevelop
/// </summary> /// </summary>
byte[] fileData; byte[] fileData;
internal OpenedFile(string fileName) #region IsDirty
{ bool isDirty;
this.fileName = fileName; public event EventHandler IsDirtyChanged;
isUntitled = false;
}
internal OpenedFile(byte[] fileData) /// <summary>
{ /// Gets/sets if the file is has unsaved changes.
this.fileName = null; /// </summary>
this.fileData = fileData; public bool IsDirty {
isUntitled = true; get { return isDirty;}
MakeDirty(); set {
if (isDirty != value) {
isDirty = value;
if (IsDirtyChanged != null) {
IsDirtyChanged(this, EventArgs.Empty);
}
}
}
} }
/// <summary> /// <summary>
/// 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.
/// </summary> /// </summary>
public static OpenedFile CreateDummyOpenedFile(string name, bool isUntitled) public virtual void MakeDirty()
{ {
if (isUntitled) { if (!inLoadOperation) {
OpenedFile f = new OpenedFile(new byte[0]); this.IsDirty = true;
f.isConnectedWithFileService = false;
f.FileName = name;
return f;
} else {
OpenedFile f = new OpenedFile(name);
f.isConnectedWithFileService = false;
return f;
} }
} }
#endregion
bool isUntitled;
/// <summary>
/// Gets if the file is untitled. Untitled files show a "Save as" dialog when they are saved.
/// </summary>
public bool IsUntitled { public bool IsUntitled {
get { return isUntitled; } get { return isUntitled; }
protected set { isUntitled = value; }
} }
string fileName;
/// <summary>
/// Gets the name of the file.
/// </summary>
public string FileName { public string FileName {
get { return fileName; } get { return fileName; }
set { set {
@ -75,25 +83,71 @@ namespace ICSharpCode.SharpDevelop
value = FileUtility.NormalizePath(value); value = FileUtility.NormalizePath(value);
if (fileName != value) { if (fileName != value) {
if (isConnectedWithFileService) { ChangeFileName(value);
FileService.OpenedFileFileNameChange(this, fileName, value);
}
fileName = value;
if (FileNameChanged != null) {
FileNameChanged(this, EventArgs.Empty);
}
} }
} }
} }
protected virtual void ChangeFileName(string newValue)
{
fileName = newValue;
if (FileNameChanged != null) {
FileNameChanged(this, EventArgs.Empty);
}
}
/// <summary>
/// Occurs when the file name has changed.
/// </summary>
public event EventHandler FileNameChanged; public event EventHandler FileNameChanged;
/// <summary>
/// Use this method to save the file to disk using a new name.
/// </summary>
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()
{
}
/// <summary>
/// Forces initialization of the specified view.
/// </summary>
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;
}
}
}
}
/// <summary> /// <summary>
/// Gets the list of view contents registered with this opened file. /// Gets the list of view contents registered with this opened file.
/// </summary> /// </summary>
public IList<IViewContent> RegisteredViewContents { public abstract IList<IViewContent> RegisteredViewContents {
get { return registeredViews.AsReadOnly(); } get;
} }
/// <summary> /// <summary>
@ -110,12 +164,12 @@ namespace ICSharpCode.SharpDevelop
/// <summary> /// <summary>
/// Opens the file for reading. /// Opens the file for reading.
/// </summary> /// </summary>
public Stream OpenRead() public virtual Stream OpenRead()
{ {
if (fileData != null) { if (fileData != null) {
return new MemoryStream(fileData, false); return new MemoryStream(fileData, false);
} else { } 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 /// 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. /// with the file is saved, e.g. for .resx files created by the forms designer.
/// </remarks> /// </remarks>
public void SetData(byte[] fileData) public virtual void SetData(byte[] fileData)
{ {
if (fileData == null) if (fileData == null)
throw new ArgumentNullException("fileData"); throw new ArgumentNullException("fileData");
@ -141,16 +195,12 @@ namespace ICSharpCode.SharpDevelop
this.fileData = fileData; this.fileData = fileData;
} }
public void SaveToDisk(string newFileName) /// <summary>
{ /// Save the file to disk using the current name.
this.FileName = newFileName; /// </summary>
isUntitled = false; public virtual void SaveToDisk()
SaveToDisk();
}
public void SaveToDisk()
{ {
if (isUntitled) if (IsUntitled)
throw new InvalidOperationException("Cannot save an untitled file to disk!"); 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) { if (currentView != null) {
SaveCurrentViewToStream(fs); SaveCurrentViewToStream(fs);
} else { } else {
@ -187,7 +237,6 @@ namespace ICSharpCode.SharpDevelop
// /// </summary> // /// </summary>
// public event EventHandler SavedCurrentView; // public event EventHandler SavedCurrentView;
bool inSaveOperation;
void SaveCurrentViewToStream(Stream stream) void SaveCurrentViewToStream(Stream stream)
{ {
@ -203,7 +252,7 @@ namespace ICSharpCode.SharpDevelop
// SavedCurrentView(this, EventArgs.Empty); // SavedCurrentView(this, EventArgs.Empty);
} }
void SaveCurrentView() protected void SaveCurrentView()
{ {
using (MemoryStream memoryStream = new MemoryStream()) { using (MemoryStream memoryStream = new MemoryStream()) {
SaveCurrentViewToStream(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 protected void SwitchedToView(IViewContent newView)
void ViewDisposed(object sender, EventArgs e)
{
Debug.Fail("View was disposed while still registered with OpenedFile!");
}
#endif
/// <summary>
/// Forces initialization of the specified view.
/// </summary>
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)
{ {
if (currentView != null) { if (currentView != null) {
if (newView.SupportsSwitchToThisWithoutSaveLoad(this, currentView) if (newView.SupportsSwitchToThisWithoutSaveLoad(this, currentView)
@ -333,7 +290,7 @@ namespace ICSharpCode.SharpDevelop
} }
} }
public void ReloadFromDisk() public virtual void ReloadFromDisk()
{ {
fileData = null; fileData = null;
if (currentView != null) { if (currentView != null) {
@ -347,157 +304,116 @@ namespace ICSharpCode.SharpDevelop
} }
} }
} }
}
/* sealed class FileServiceOpenedFile : OpenedFile
internal void ChangeView(IViewContent newView) {
List<IViewContent> registeredViews = new List<IViewContent>();
protected override void ChangeFileName(string newValue)
{ {
if (currentView != null && currentView != newView) { FileService.OpenedFileFileNameChange(this, this.FileName, newValue);
SaveCurrentView(); base.ChangeFileName(newValue);
}
using (Stream sourceStream = OpenRead()) {
currentView = newView;
fileData = null;
newView.Load(this, sourceStream);
}
} }
*/
bool isDirty;
public event EventHandler IsDirtyChanged;
public bool IsDirty {
get { return isDirty;}
set {
if (isDirty != value) {
isDirty = value;
if (IsDirtyChanged != null) { internal FileServiceOpenedFile(string fileName)
IsDirtyChanged(this, EventArgs.Empty); {
} this.FileName = fileName;
} IsUntitled = false;
}
} }
bool inLoadOperation; internal FileServiceOpenedFile(byte[] fileData)
{
this.FileName = null;
SetData(fileData);
IsUntitled = true;
MakeDirty();
}
/// <summary> /// <summary>
/// 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.
/// </summary> /// </summary>
public void MakeDirty() public override IList<IViewContent> RegisteredViewContents {
get { return registeredViews.AsReadOnly(); }
}
public override void ForceInitializeView(IViewContent view)
{ {
if (!inLoadOperation) { if (view == null)
this.IsDirty = true; throw new ArgumentNullException("view");
} if (!registeredViews.Contains(view))
throw new ArgumentException("registeredViews must contain view");
base.ForceInitializeView(view);
} }
#region FileChangeWatcher public override void RegisterView(IViewContent view)
internal sealed class FileChangeWatcher //: IDisposable
{ {
/*FileSystemWatcher watcher; if (view == null)
bool wasChangedExternally = false; throw new ArgumentNullException("view");
string fileName; if (registeredViews.Contains(view))
AbstractViewContent viewContent; throw new ArgumentException("registeredViews already contains view");
public FileChangeWatcher(AbstractViewContent viewContent)
{
this.viewContent = viewContent;
WorkbenchSingleton.MainForm.Activated += GotFocusEvent;
}
*/
public static bool DetectExternalChangesOption { registeredViews.Add(view);
get {
return PropertyService.Get("SharpDevelop.FileChangeWatcher.DetectExternalChanges", true);
}
set {
PropertyService.Set("SharpDevelop.FileChangeWatcher.DetectExternalChanges", value);
}
}
public static bool AutoLoadExternalChangesOption { if (WorkbenchSingleton.Workbench != null) {
get { WorkbenchSingleton.Workbench.ActiveViewContentChanged += WorkbenchActiveViewContentChanged;
return PropertyService.Get("SharpDevelop.FileChangeWatcher.AutoLoadExternalChanges", true); if (WorkbenchSingleton.Workbench.ActiveViewContent == view) {
} SwitchedToView(view);
set {
PropertyService.Set("SharpDevelop.FileChangeWatcher.AutoLoadExternalChanges", value);
} }
} }
#if DEBUG
view.Disposed += ViewDisposed;
#endif
}
/* public override void UnregisterView(IViewContent view)
public void Dispose() {
{ if (view == null)
WorkbenchSingleton.MainForm.Activated -= GotFocusEvent; throw new ArgumentNullException("view");
if (watcher != null) { Debug.Assert(registeredViews.Contains(view));
watcher.Dispose();
}
}
public void Disable() if (WorkbenchSingleton.Workbench != null) {
{ WorkbenchSingleton.Workbench.ActiveViewContentChanged -= WorkbenchActiveViewContentChanged;
if (watcher != null) {
watcher.EnableRaisingEvents = false;
}
} }
#if DEBUG
view.Disposed -= ViewDisposed;
#endif
public void SetWatcher(string fileName) registeredViews.Remove(view);
{ if (registeredViews.Count > 0) {
this.fileName = fileName; if (currentView == view) {
if (DetectExternalChangesOption == false) SaveCurrentView();
return; currentView = null;
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;
} }
} else {
// all views to the file were closed
FileService.OpenedFileClosed(this);
} }
}
void OnFileChangedEvent(object sender, FileSystemEventArgs e) public override void CloseIfAllViewsClosed()
{ {
if (e.ChangeType != WatcherChangeTypes.Deleted) { if (registeredViews.Count == 0) {
wasChangedExternally = true; FileService.OpenedFileClosed(this);
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 DEBUG
{ void ViewDisposed(object sender, EventArgs e)
if (wasChangedExternally) { {
wasChangedExternally = false; Debug.Fail("View was disposed while still registered with OpenedFile!");
}
string message = StringParser.Parse("${res:ICSharpCode.SharpDevelop.DefaultEditor.Gui.Editor.TextEditorDisplayBinding.FileAlteredMessage}", new string[,] {{"File", Path.GetFullPath(fileName)}}); #endif
if ((AutoLoadExternalChangesOption && viewContent.IsDirty == false)
|| MessageBox.Show(message, void WorkbenchActiveViewContentChanged(object sender, EventArgs e)
StringParser.Parse("${res:MainWindow.DialogName}"), {
MessageBoxButtons.YesNo, IViewContent newView = WorkbenchSingleton.Workbench.ActiveViewContent;
MessageBoxIcon.Question) == DialogResult.Yes)
{ if (!registeredViews.Contains(newView))
if (File.Exists(fileName)) { return;
viewContent.Load(fileName);
} SwitchedToView(newView);
} else {
viewContent.IsDirty = true;
}
}
}
*/
} }
#endregion
} }
} }

Loading…
Cancel
Save