Browse Source

Fixed SD2-1519 - Forms designer moves deleted fields to designer code file. Designer now loads all source files that contain parts of the designed class.

Added support for removing and replacing field declarations outside of the designer code file.
(Changes are identical to the patch I posted in the tracker.)

git-svn-id: svn://svn.sharpdevelop.net/sharpdevelop/branches/3.0@3790 1ccf3a8d-04fe-1044-b7c0-cef0b8235c61
shortcuts
Christian Hornung 17 years ago
parent
commit
3ec594562e
  1. 6
      src/AddIns/BackendBindings/Python/PythonBinding/Project/Src/PythonDesignerGenerator.cs
  2. 5
      src/AddIns/BackendBindings/Python/PythonBinding/Test/Utils/MockDesignerGenerator.cs
  3. 34
      src/AddIns/BackendBindings/WixBinding/Project/Src/Gui/WixDialogDesigner.cs
  4. 6
      src/AddIns/BackendBindings/WixBinding/Project/Src/Gui/WixDialogDesignerGenerator.cs
  5. 1
      src/AddIns/DisplayBindings/FormsDesigner/Project/FormsDesigner.csproj
  6. 101
      src/AddIns/DisplayBindings/FormsDesigner/Project/Src/DesignerGenerator/AbstractDesignerGenerator.cs
  7. 10
      src/AddIns/DisplayBindings/FormsDesigner/Project/Src/DesignerGenerator/IDesignerGenerator.cs
  8. 6
      src/AddIns/DisplayBindings/FormsDesigner/Project/Src/DesignerGenerator/XmlDesignerGenerator.cs
  9. 217
      src/AddIns/DisplayBindings/FormsDesigner/Project/Src/DesignerSourceCodeStorage.cs
  10. 187
      src/AddIns/DisplayBindings/FormsDesigner/Project/Src/DesignerViewContent.cs

6
src/AddIns/BackendBindings/Python/PythonBinding/Project/Src/PythonDesignerGenerator.cs

@ -9,6 +9,7 @@ using System; @@ -9,6 +9,7 @@ using System;
using System.CodeDom;
using System.CodeDom.Compiler;
using System.Collections;
using System.Collections.Generic;
using System.ComponentModel;
using System.Drawing;
using System.Reflection;
@ -64,9 +65,10 @@ namespace ICSharpCode.PythonBinding @@ -64,9 +65,10 @@ namespace ICSharpCode.PythonBinding
this.viewContent = null;
}
public OpenedFile DetermineDesignerCodeFile()
public IEnumerable<OpenedFile> GetSourceFiles(out OpenedFile designerCodeFile)
{
return this.ViewContent.PrimaryFile;
designerCodeFile = this.ViewContent.PrimaryFile;
return new [] {designerCodeFile};
}
public void MergeFormChanges(CodeCompileUnit unit)

5
src/AddIns/BackendBindings/Python/PythonBinding/Test/Utils/MockDesignerGenerator.cs

@ -48,9 +48,10 @@ namespace PythonBinding.Tests.Utils @@ -48,9 +48,10 @@ namespace PythonBinding.Tests.Utils
this.viewContent = null;
}
public ICSharpCode.SharpDevelop.OpenedFile DetermineDesignerCodeFile()
public System.Collections.Generic.IEnumerable<ICSharpCode.SharpDevelop.OpenedFile> GetSourceFiles(out ICSharpCode.SharpDevelop.OpenedFile designerCodeFile)
{
return this.viewContent.DesignerCodeFile;
designerCodeFile = this.viewContent.DesignerCodeFile;
return new [] {designerCodeFile};
}
public void MergeFormChanges(CodeCompileUnit unit)

34
src/AddIns/BackendBindings/WixBinding/Project/Src/Gui/WixDialogDesigner.cs

@ -7,7 +7,6 @@ @@ -7,7 +7,6 @@
using System;
using System.Collections.ObjectModel;
using System.Diagnostics;
using System.IO;
using System.Xml;
@ -18,7 +17,6 @@ using ICSharpCode.SharpDevelop.DefaultEditor.Gui.Editor; @@ -18,7 +17,6 @@ using ICSharpCode.SharpDevelop.DefaultEditor.Gui.Editor;
using ICSharpCode.SharpDevelop.Gui;
using ICSharpCode.SharpDevelop.Project;
using ICSharpCode.TextEditor;
using ICSharpCode.TextEditor.Document;
namespace ICSharpCode.WixBinding
{
@ -61,28 +59,6 @@ namespace ICSharpCode.WixBinding @@ -61,28 +59,6 @@ namespace ICSharpCode.WixBinding
return null;
}
// The FormsDesignerViewContent normally operates independently of any
// text editor. The following overrides connect the forms designer
// directly to the underlying XML text editor so that the caret positioning
// and text selection operations done by the WiX designer actually
// become visible in the text editor.
public override IDocument PrimaryFileDocument {
get { return ((ITextEditorControlProvider)this.PrimaryViewContent).TextEditorControl.Document; }
}
public override IDocument DesignerCodeFileDocument {
get { return this.PrimaryFileDocument; }
}
public override System.Text.Encoding PrimaryFileEncoding {
get { return ((ITextEditorControlProvider)this.PrimaryViewContent).TextEditorControl.Encoding; }
}
public override System.Text.Encoding DesignerCodeFileEncoding {
get { return this.PrimaryFileEncoding; }
}
/// <summary>
/// Attempts to open the Wix dialog from the document currently
/// associated with this designer.
@ -106,6 +82,16 @@ namespace ICSharpCode.WixBinding @@ -106,6 +82,16 @@ namespace ICSharpCode.WixBinding
protected override void LoadInternal(OpenedFile file, Stream stream)
{
if (file == this.PrimaryFile) {
// The FormsDesignerViewContent normally operates independently of any
// text editor. The following statements connect the forms designer
// directly to the underlying XML text editor so that the caret positioning
// and text selection operations done by the WiX designer actually
// become visible in the text editor.
if (!this.SourceCodeStorage.ContainsFile(file)) {
TextEditorControl editor = ((ITextEditorControlProvider)this.PrimaryViewContent).TextEditorControl;
this.SourceCodeStorage.AddFile(file, editor.Document, editor.Encoding ?? ParserService.DefaultFileEncoding, true);
}
try {
if (!ignoreDialogIdSelectedInTextEditor) {
string dialogId = GetDialogIdSelectedInTextEditor();

6
src/AddIns/BackendBindings/WixBinding/Project/Src/Gui/WixDialogDesignerGenerator.cs

@ -9,6 +9,7 @@ using System; @@ -9,6 +9,7 @@ using System;
using System.CodeDom;
using System.CodeDom.Compiler;
using System.Collections;
using System.Collections.Generic;
using System.ComponentModel;
using System.IO;
using System.Reflection;
@ -58,9 +59,10 @@ namespace ICSharpCode.WixBinding @@ -58,9 +59,10 @@ namespace ICSharpCode.WixBinding
get { return this.view; }
}
public OpenedFile DetermineDesignerCodeFile()
public IEnumerable<OpenedFile> GetSourceFiles(out OpenedFile designerCodeFile)
{
return this.view.PrimaryFile;
designerCodeFile = this.view.PrimaryFile;
return new [] {designerCodeFile};
}
public void Attach(FormsDesignerViewContent viewContent)

1
src/AddIns/DisplayBindings/FormsDesigner/Project/FormsDesigner.csproj

@ -64,6 +64,7 @@ @@ -64,6 +64,7 @@
<Compile Include="Src\DesignerLoader\AbstractCodeDomDesignerLoader.cs" />
<Compile Include="Src\DesignerLoader\NRefactoryDesignerLoader.cs" />
<Compile Include="Src\DesignerLoader\XmlDesignerLoader.cs" />
<Compile Include="Src\DesignerSourceCodeStorage.cs" />
<Compile Include="Src\Gui\ImageResourceEditorDialog.cs" />
<Compile Include="Src\Gui\ImageResourceEditorDialog.Designer.cs">
<DependentUpon>ImageResourceEditorDialog.cs</DependentUpon>

101
src/AddIns/DisplayBindings/FormsDesigner/Project/Src/DesignerGenerator/AbstractDesignerGenerator.cs

@ -12,6 +12,7 @@ using System.Collections; @@ -12,6 +12,7 @@ using System.Collections;
using System.Collections.Generic;
using System.ComponentModel;
using System.IO;
using System.Linq;
using System.Reflection;
using ICSharpCode.Core;
@ -70,7 +71,7 @@ namespace ICSharpCode.FormsDesigner @@ -70,7 +71,7 @@ namespace ICSharpCode.FormsDesigner
this.viewContent = null;
}
public OpenedFile DetermineDesignerCodeFile()
public IEnumerable<OpenedFile> GetSourceFiles(out OpenedFile designerCodeFile)
{
// get new initialize components
ParseInformation info = ParserService.ParseFile(this.viewContent.PrimaryFileName, this.viewContent.PrimaryFileContent, false);
@ -80,9 +81,20 @@ namespace ICSharpCode.FormsDesigner @@ -80,9 +81,20 @@ namespace ICSharpCode.FormsDesigner
this.currentClassPart = c;
this.initializeComponents = FormsDesignerSecondaryDisplayBinding.GetInitializeComponents(c);
if (this.initializeComponents != null) {
string designerFile = this.initializeComponents.DeclaringType.CompilationUnit.FileName;
if (designerFile != null) {
return FileService.GetOrCreateOpenedFile(designerFile);
string designerFileName = this.initializeComponents.DeclaringType.CompilationUnit.FileName;
if (designerFileName != null) {
designerCodeFile = FileService.GetOrCreateOpenedFile(designerFileName);
CompoundClass compound = c.GetCompoundClass() as CompoundClass;
if (compound == null) {
return new [] {designerCodeFile};
} else {
return compound.Parts
.Select(cl => FileService.GetOrCreateOpenedFile(cl.CompilationUnit.FileName))
.Distinct();
}
}
}
}
@ -99,12 +111,20 @@ namespace ICSharpCode.FormsDesigner @@ -99,12 +111,20 @@ namespace ICSharpCode.FormsDesigner
try {
LoggingService.Info("Remove field declaration: "+fieldName);
Reparse();
IField field = GetField(formClass, fieldName);
IField field = GetField(completeClass, fieldName);
if (field != null) {
this.RemoveFieldDeclaration(this.ViewContent.DesignerCodeFileDocument, field);
} else if ((field = GetField(completeClass, fieldName)) != null) {
// TODO: Remove the field in the part where it is declared
LoggingService.Warn("Removing field declaration in non-designer part currently not supported");
string fileName = field.DeclaringType.CompilationUnit.FileName;
LoggingService.Debug("-> Field is declared in file '" + fileName + "', Region: " + field.Region.ToString());
OpenedFile file = FileService.GetOpenedFile(fileName);
if (file == null) throw new InvalidOperationException("The file where the field is declared is not open, although it belongs to the class.");
IDocument doc = this.ViewContent.GetDocumentForFile(file);
if (doc == null) throw new InvalidOperationException("Could not get document for file '" + file.FileName + "'.");
this.RemoveFieldDeclaration(doc, field);
file.MakeDirty();
} else {
LoggingService.Warn("-> Field '" + fieldName + "' not found in class");
}
} catch (Exception ex) {
MessageService.ShowError(ex);
@ -134,18 +154,20 @@ namespace ICSharpCode.FormsDesigner @@ -134,18 +154,20 @@ namespace ICSharpCode.FormsDesigner
{
try {
Reparse();
IField oldField = GetField(formClass, newField.Name);
IField oldField = GetField(completeClass, newField.Name);
if (oldField != null) {
this.ReplaceFieldDeclaration(this.ViewContent.DesignerCodeFileDocument, oldField, GenerateFieldDeclaration(domGenerator, newField));
} else {
if ((oldField = GetField(completeClass, newField.Name)) != null) {
// TODO: Replace the field in the part where it is declared
LoggingService.Warn("Field declaration replacement in non-designer part currently not supported");
string fileName = oldField.DeclaringType.CompilationUnit.FileName;
LoggingService.Debug("-> Old field is declared in file '" + fileName + "', Region: " + oldField.Region.ToString());
OpenedFile file = FileService.GetOpenedFile(fileName);
if (file == null) throw new InvalidOperationException("The file where the field is declared is not open, although it belongs to the class.");
IDocument doc = this.ViewContent.GetDocumentForFile(file);
if (doc == null) throw new InvalidOperationException("Could not get document for file '" + file.FileName + "'.");
this.ReplaceFieldDeclaration(doc, oldField, GenerateFieldDeclaration(domGenerator, newField));
file.MakeDirty();
} else {
int endOffset = this.ViewContent.DesignerCodeFileDocument.PositionToOffset(new TextLocation(0, initializeComponents.BodyRegion.EndLine));
this.ViewContent.DesignerCodeFileDocument.Insert(endOffset, tabs + GenerateFieldDeclaration(domGenerator, newField) + Environment.NewLine);
}
}
} catch (Exception ex) {
MessageService.ShowError(ex);
}
@ -315,13 +337,18 @@ namespace ICSharpCode.FormsDesigner @@ -315,13 +337,18 @@ namespace ICSharpCode.FormsDesigner
protected void Reparse()
{
Dictionary<OpenedFile, ParseInformation> parsings = new Dictionary<OpenedFile, ParseInformation>();
ParseInformation info;
ICompilationUnit cu;
// Reparse primary file to update currentClassPart
// Reparse all source files for the designed form
foreach (KeyValuePair<OpenedFile, IDocument> entry in this.ViewContent.SourceFiles) {
parsings.Add(entry.Key, ParserService.ParseFile(entry.Key.FileName, entry.Value.TextContent, false));
}
// Update currentClassPart from PrimaryFile
this.currentClassPart = null;
if (!String.IsNullOrEmpty(this.ViewContent.PrimaryFileName)) {
info = ParserService.ParseFile(this.ViewContent.PrimaryFileName, this.ViewContent.PrimaryFileContent, false);
if (this.ViewContent.PrimaryFile != null && parsings.TryGetValue(this.ViewContent.PrimaryFile, out info)) {
cu = info.BestCompilationUnit;
foreach (IClass c in cu.Classes) {
if (FormsDesignerSecondaryDisplayBinding.BaseClassIsFormOrControl(c)) {
@ -331,19 +358,27 @@ namespace ICSharpCode.FormsDesigner @@ -331,19 +358,27 @@ namespace ICSharpCode.FormsDesigner
}
}
}
if (this.currentClassPart == null) {
LoggingService.Warn("AbstractDesignerGenerator.Reparse: Could not find designed class in primary file '" + this.ViewContent.PrimaryFile.FileName + "'");
}
} else {
LoggingService.Debug("AbstractDesignerGenerator.Reparse: Primary file is unavailable");
info = null;
}
// Reparse designer code file to update initializeComponents,
// completeClass and formClass
if (info == null || this.ViewContent.DesignerCodeFile != this.ViewContent.PrimaryFile) {
// Actual parsing is only necessary if the designer code file
// is not the same as the primary file. Otherwise we just
// reuse the parse info from above.
info = ParserService.ParseFile(this.ViewContent.DesignerCodeFile.FileName, this.ViewContent.DesignerCodeFileContent, false);
// Update initializeComponents, completeClass and formClass
// from designer code file
this.completeClass = null;
this.formClass = null;
this.initializeComponents = null;
if (this.ViewContent.DesignerCodeFile == null ||
!parsings.TryGetValue(this.ViewContent.DesignerCodeFile, out info)) {
LoggingService.Warn("AbstractDesignerGenerator.Reparse: Designer source code file is unavailable");
if (this.currentClassPart != null) {
this.completeClass = this.currentClassPart.GetCompoundClass();
}
return;
}
cu = info.BestCompilationUnit;
foreach (IClass c in cu.Classes) {
if (FormsDesignerSecondaryDisplayBinding.BaseClassIsFormOrControl(c)) {
@ -362,6 +397,10 @@ namespace ICSharpCode.FormsDesigner @@ -362,6 +397,10 @@ namespace ICSharpCode.FormsDesigner
}
}
}
if (this.completeClass == null || this.formClass == null) {
LoggingService.Warn("AbstractDesignerGenerator.Reparse: Could not find InitializeComponents in designer source code file '" + this.ViewContent.DesignerCodeFile.FileName + "'");
}
}
protected static string GetIndentation(string line)
@ -396,10 +435,10 @@ namespace ICSharpCode.FormsDesigner @@ -396,10 +435,10 @@ namespace ICSharpCode.FormsDesigner
foreach (IMethod method in completeClass.Methods) {
if (method.Name == eventMethodName) {
file = method.DeclaringType.CompilationUnit.FileName;
if (FileUtility.IsEqualFileName(file, this.ViewContent.PrimaryFileName)) {
position = GetCursorLine(this.ViewContent.PrimaryFileDocument, method);
} else if (FileUtility.IsEqualFileName(file, this.ViewContent.DesignerCodeFile.FileName)) {
position = GetCursorLine(this.ViewContent.DesignerCodeFileDocument, method);
OpenedFile openedFile = FileService.GetOpenedFile(file);
IDocument doc;
if (openedFile != null && (doc = this.ViewContent.GetDocumentForFile(openedFile)) != null) {
position = GetCursorLine(doc, method);
} else {
try {
position = GetCursorLine(FindReferencesAndRenameHelper.GetDocumentInformation(file).CreateDocument(), method);

10
src/AddIns/DisplayBindings/FormsDesigner/Project/Src/DesignerGenerator/IDesignerGenerator.cs

@ -9,6 +9,7 @@ using System; @@ -9,6 +9,7 @@ using System;
using System.CodeDom;
using System.CodeDom.Compiler;
using System.Collections;
using System.Collections.Generic;
using System.ComponentModel;
using System.Reflection;
@ -25,10 +26,13 @@ namespace ICSharpCode.FormsDesigner @@ -25,10 +26,13 @@ namespace ICSharpCode.FormsDesigner
void Detach();
FormsDesignerViewContent ViewContent { get; }
/// <summary>
/// Gets the OpenedFile for the file which contains the code to be modified by the forms designer.
/// This method must never return null. If it cannot find that file, it must throw an exception.
/// Gets the collection of OpenedFiles that contain code which belongs
/// to the designed form, not including resource files.
/// </summary>
OpenedFile DetermineDesignerCodeFile();
/// <param name="designerCodeFile">Receives the file which contains the code to be modified by the forms designer.</param>
/// <returns>A collection of OpenedFiles that contain code which belongs to the designed form.</returns>
/// <remarks>The returned collection must include the <paramref name="designerCodeFile"/>.</remarks>
IEnumerable<OpenedFile> GetSourceFiles(out OpenedFile designerCodeFile);
void MergeFormChanges(CodeCompileUnit unit);
bool InsertComponentEvent(IComponent component, EventDescriptor edesc, string eventMethodName, string body, out string file, out int position);
ICollection GetCompatibleMethods(EventDescriptor edesc);

6
src/AddIns/DisplayBindings/FormsDesigner/Project/Src/DesignerGenerator/XmlDesignerGenerator.cs

@ -9,6 +9,7 @@ using System; @@ -9,6 +9,7 @@ using System;
using System.CodeDom;
using System.CodeDom.Compiler;
using System.Collections;
using System.Collections.Generic;
using System.ComponentModel;
using System.ComponentModel.Design;
using System.Drawing;
@ -45,9 +46,10 @@ namespace ICSharpCode.FormsDesigner @@ -45,9 +46,10 @@ namespace ICSharpCode.FormsDesigner
this.viewContent = null;
}
public OpenedFile DetermineDesignerCodeFile()
public IEnumerable<OpenedFile> GetSourceFiles(out OpenedFile designerCodeFile)
{
return this.viewContent.PrimaryFile;
designerCodeFile = this.viewContent.PrimaryFile;
return new [] {designerCodeFile};
}
public void MergeFormChanges(CodeCompileUnit unit)

217
src/AddIns/DisplayBindings/FormsDesigner/Project/Src/DesignerSourceCodeStorage.cs

@ -0,0 +1,217 @@ @@ -0,0 +1,217 @@
// <file>
// <copyright see="prj:///doc/copyright.txt"/>
// <license see="prj:///doc/license.txt"/>
// <owner name="Christian Hornung" email="chhornung@googlemail.com"/>
// <version>$Revision$</version>
// </file>
using System;
using System.Collections.Generic;
using System.IO;
using System.Text;
using ICSharpCode.Core;
using ICSharpCode.SharpDevelop;
using ICSharpCode.TextEditor.Document;
using ICSharpCode.TextEditor.Util;
namespace ICSharpCode.FormsDesigner
{
/// <summary>
/// Manages the source code files and their content associated with
/// an open forms designer view.
/// </summary>
public sealed class DesignerSourceCodeStorage : IEnumerable<KeyValuePair<OpenedFile, IDocument>>
{
readonly Dictionary<OpenedFile, FileContent> fileContents = new Dictionary<OpenedFile, FileContent>();
OpenedFile designerCodeFile;
public DesignerSourceCodeStorage()
{
}
public OpenedFile DesignerCodeFile {
get { return this.designerCodeFile; }
set {
if (value != null && !this.fileContents.ContainsKey(value)) {
throw new InvalidOperationException("The specified DesignerCodeFile '" + value.FileName + "' is not registered with this DesignerSourceCodeStorage instance.");
}
this.designerCodeFile = value;
}
}
/// <summary>
/// Gets the <see cref="IDocument"/> associated with the specified file or
/// <c>null</c> if the file is not registered with the current instance.
/// </summary>
public IDocument this[OpenedFile file] {
get {
FileContent c;
if (this.fileContents.TryGetValue(file, out c)) {
return c.Document;
} else {
return null;
}
}
}
public IEnumerator<KeyValuePair<OpenedFile, IDocument>> GetEnumerator()
{
foreach (KeyValuePair<OpenedFile, FileContent> entry in this.fileContents) {
yield return new KeyValuePair<OpenedFile, IDocument>(entry.Key, entry.Value.Document);
}
}
System.Collections.IEnumerator System.Collections.IEnumerable.GetEnumerator()
{
return this.GetEnumerator();
}
public void LoadFile(OpenedFile file, Stream stream)
{
if (stream == null)
throw new ArgumentNullException("stream");
if (file == null)
throw new ArgumentNullException("file");
FileContent c;
if (!this.fileContents.TryGetValue(file, out c)) {
c = new FileContent();
this.fileContents.Add(file, c);
}
c.LoadFrom(stream);
}
public void SaveFile(OpenedFile file, Stream stream)
{
if (stream == null)
throw new ArgumentNullException("stream");
if (file == null)
throw new ArgumentNullException("file");
FileContent c;
if (!this.fileContents.TryGetValue(file, out c)) {
throw new InvalidOperationException("Cannot save file '" + file.FileName + "' because this file is not registered with this DesignerSourceCodeStorage instance.");
}
c.SaveTo(stream);
}
/// <summary>
/// Adds a file with an empty document.
/// </summary>
public void AddFile(OpenedFile file)
{
this.fileContents.Add(file, new FileContent());
}
/// <summary>
/// Adds a file with an empty document and the specified encoding.
/// </summary>
public void AddFile(OpenedFile file, Encoding encoding)
{
this.fileContents.Add(file, new FileContent(encoding));
}
/// <summary>
/// Adds a file with the specified document and the specified encoding.
/// </summary>
public void AddFile(OpenedFile file, IDocument document, Encoding encoding)
{
this.fileContents.Add(file, new FileContent(document, encoding));
}
/// <summary>
/// Adds a file with the specified document and the specified encoding.
/// </summary>
/// <param name="doNotLoad">When true, the SourceCodeStorage will not load the stream content into the document when the view is loaded. Use this when the document content is already managed elsewhere.</param>
public void AddFile(OpenedFile file, IDocument document, Encoding encoding, bool doNotLoad)
{
this.fileContents.Add(file, new FileContent(document, encoding, doNotLoad));
}
public bool ContainsFile(OpenedFile file)
{
return this.fileContents.ContainsKey(file);
}
public bool RemoveFile(OpenedFile file)
{
return this.fileContents.Remove(file);
}
public Encoding GetFileEncoding(OpenedFile file)
{
if (file == null)
throw new ArgumentNullException("file");
FileContent c;
if (!this.fileContents.TryGetValue(file, out c)) {
throw new InvalidOperationException("Cannot get Encoding for file '" + file.FileName + "' because this file is not registered with this DesignerSourceCodeStorage instance.");
}
return c.Encoding;
}
/// <summary>
/// Stores the content of a file in an <see cref="IDocument"/>
/// along with its encoding.
/// </summary>
sealed class FileContent
{
static readonly DocumentFactory documentFactory = new DocumentFactory();
Encoding encoding;
readonly IDocument document;
readonly bool doNotLoad;
public FileContent()
: this(ParserService.DefaultFileEncoding)
{
}
public FileContent(Encoding encoding)
: this(documentFactory.CreateDocument(), encoding)
{
}
public FileContent(IDocument document, Encoding encoding)
: this(document, encoding, false)
{
}
public FileContent(IDocument document, Encoding encoding, bool doNotLoad)
{
if (document == null)
throw new ArgumentNullException("document");
if (encoding == null)
throw new ArgumentNullException("encoding");
this.document = document;
this.encoding = encoding;
this.doNotLoad = doNotLoad;
}
public IDocument Document {
get { return this.document; }
}
public Encoding Encoding {
get { return this.encoding; }
}
public void LoadFrom(Stream stream)
{
if (this.doNotLoad)
return;
this.encoding = ParserService.DefaultFileEncoding;
this.Document.TextContent = FileReader.ReadFileContent(stream, ref this.encoding);
}
public void SaveTo(Stream stream)
{
using(StreamWriter writer = new StreamWriter(stream, this.encoding)) {
writer.Write(this.Document.TextContent);
}
}
}
}
}

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

@ -13,6 +13,7 @@ using System.ComponentModel.Design; @@ -13,6 +13,7 @@ using System.ComponentModel.Design;
using System.ComponentModel.Design.Serialization;
using System.Drawing;
using System.IO;
using System.Linq;
using System.Text;
using System.Windows.Forms;
@ -23,7 +24,6 @@ using ICSharpCode.SharpDevelop; @@ -23,7 +24,6 @@ using ICSharpCode.SharpDevelop;
using ICSharpCode.SharpDevelop.DefaultEditor.Gui.Editor;
using ICSharpCode.SharpDevelop.Gui;
using ICSharpCode.TextEditor.Document;
using ICSharpCode.TextEditor.Util;
namespace ICSharpCode.FormsDesigner
{
@ -41,11 +41,7 @@ namespace ICSharpCode.FormsDesigner @@ -41,11 +41,7 @@ namespace ICSharpCode.FormsDesigner
FormsDesignerUndoEngine undoEngine;
TypeResolutionService typeResolutionService;
Encoding primaryFileEncoding;
readonly IDocument primaryFileDocument = new DocumentFactory().CreateDocument();
Encoding designerCodeFileEncoding;
OpenedFile designerCodeFile;
IDocument designerCodeFileDocument;
readonly DesignerSourceCodeStorage sourceCodeStorage;
readonly Dictionary<Type, TypeDescriptionProvider> addedTypeDescriptionProviders = new Dictionary<Type, TypeDescriptionProvider>();
@ -64,11 +60,11 @@ namespace ICSharpCode.FormsDesigner @@ -64,11 +60,11 @@ namespace ICSharpCode.FormsDesigner
}
public OpenedFile DesignerCodeFile {
get { return this.designerCodeFile; }
get { return this.sourceCodeStorage.DesignerCodeFile; }
}
public virtual IDocument PrimaryFileDocument {
get { return this.primaryFileDocument; }
public IDocument PrimaryFileDocument {
get { return this.sourceCodeStorage[this.PrimaryFile]; }
}
public string PrimaryFileContent {
@ -76,12 +72,14 @@ namespace ICSharpCode.FormsDesigner @@ -76,12 +72,14 @@ namespace ICSharpCode.FormsDesigner
set { this.PrimaryFileDocument.TextContent = value; }
}
public virtual Encoding PrimaryFileEncoding {
get { return this.primaryFileEncoding; }
public IDocument DesignerCodeFileDocument {
get {
if (this.sourceCodeStorage.DesignerCodeFile == null) {
return null;
} else {
return this.sourceCodeStorage[this.sourceCodeStorage.DesignerCodeFile];
}
}
public virtual IDocument DesignerCodeFileDocument {
get { return this.designerCodeFileDocument; }
}
public string DesignerCodeFileContent {
@ -89,19 +87,17 @@ namespace ICSharpCode.FormsDesigner @@ -89,19 +87,17 @@ namespace ICSharpCode.FormsDesigner
set { this.DesignerCodeFileDocument.TextContent = value; }
}
public virtual Encoding DesignerCodeFileEncoding {
get { return this.designerCodeFileEncoding; }
}
public IDocument GetDocumentForFile(OpenedFile file)
{
if (file == this.DesignerCodeFile) {
return this.DesignerCodeFileDocument;
} else if (file == this.PrimaryFile) {
return this.PrimaryFileDocument;
} else {
return null;
return this.sourceCodeStorage[file];
}
public IEnumerable<KeyValuePair<OpenedFile, IDocument>> SourceFiles {
get { return this.sourceCodeStorage; }
}
protected DesignerSourceCodeStorage SourceCodeStorage {
get { return this.sourceCodeStorage; }
}
public IViewContent PrimaryViewContent {
@ -131,6 +127,7 @@ namespace ICSharpCode.FormsDesigner @@ -131,6 +127,7 @@ namespace ICSharpCode.FormsDesigner
this.UserControl = this.pleaseWaitLabel;
this.sourceCodeStorage = new DesignerSourceCodeStorage();
this.resourceStore = new ResourceStore(this);
// null check is required to support running in unit test mode
@ -162,59 +159,73 @@ namespace ICSharpCode.FormsDesigner @@ -162,59 +159,73 @@ namespace ICSharpCode.FormsDesigner
public FormsDesignerViewContent(IViewContent primaryViewContent, OpenedFile mockFile)
: this(primaryViewContent)
{
this.primaryFileDocument = new DocumentFactory().CreateDocument();
this.designerCodeFileDocument = this.primaryFileDocument;
this.designerCodeFileEncoding = System.Text.Encoding.UTF8;
this.designerCodeFile = mockFile;
this.sourceCodeStorage.AddFile(mockFile, Encoding.UTF8);
this.sourceCodeStorage.DesignerCodeFile = mockFile;
}
bool inMasterLoadOperation;
protected override void LoadInternal(OpenedFile file, System.IO.Stream stream)
{
LoggingService.Debug("Forms designer: Load " + file.FileName);
LoggingService.Debug("Forms designer: Load " + file.FileName + "; inMasterLoadOperation=" + this.inMasterLoadOperation);
if (file == this.PrimaryFile) {
if (inMasterLoadOperation) {
this.primaryFileEncoding = ParserService.DefaultFileEncoding;
this.primaryFileDocument.TextContent = FileReader.ReadFileContent(stream, ref this.primaryFileEncoding);
if (this.sourceCodeStorage.ContainsFile(file)) {
LoggingService.Debug("Forms designer: Loading " + file.FileName + " in source code storage");
this.sourceCodeStorage.LoadFile(file, stream);
} else {
LoggingService.Debug("Forms designer: Loading " + file.FileName + " in resource store");
this.resourceStore.Load(file, stream);
}
LoggingService.Debug("Forms designer: Determining designer code file for " + file.FileName);
OpenedFile newDesignerCodeFile = this.generator.DetermineDesignerCodeFile();
if (newDesignerCodeFile == null) {
throw new InvalidOperationException("The designer code file could not be determined.");
} else if (file == this.PrimaryFile || this.sourceCodeStorage.ContainsFile(file)) {
if (this.loader != null && this.loader.Loading) {
throw new InvalidOperationException("Designer loading a source code file while DesignerLoader is loading and the view is not in a master load operation. This must not happen.");
}
if (this.designerCodeFile != null && newDesignerCodeFile != this.designerCodeFile) {
this.Files.Remove(this.designerCodeFile);
if (this.designSurface != null) {
this.UnloadDesigner();
}
this.designerCodeFile = newDesignerCodeFile;
if (this.designerCodeFile == this.PrimaryFile) {
this.inMasterLoadOperation = true;
LoggingService.Debug("Forms designer: Designer code file is equal to primary file. Reloading designer.");
try {
this.UnloadDesigner();
this.designerCodeFileEncoding = this.PrimaryFileEncoding;
this.designerCodeFileDocument = this.PrimaryFileDocument;
this.LoadAndDisplayDesigner();
this.sourceCodeStorage.LoadFile(file, stream);
} else if (!this.Files.Contains(this.designerCodeFile)) {
LoggingService.Debug("Forms designer: Adding designer code file " + this.designerCodeFile.FileName);
this.Files.Insert(1, this.designerCodeFile);
} else if (this.HasLoadError || this.designSurface == null || !this.designSurface.IsLoaded) {
LoggingService.Debug("Forms designer: Having a load error. Reloading designer.");
this.ReloadDesignerFromMemory();
LoggingService.Debug("Forms designer: Determining designer source files for " + file.FileName);
OpenedFile newDesignerCodeFile;
IEnumerable<OpenedFile> sourceFiles = this.generator.GetSourceFiles(out newDesignerCodeFile);
if (sourceFiles == null || newDesignerCodeFile == null) {
throw new FormsDesignerLoadException("The designer source files could not be determined.");
}
} else if (file == this.DesignerCodeFile) {
// Unload all source files from the view which are no longer in the returned collection
foreach (OpenedFile f in this.Files.Except(sourceFiles).ToArray()) {
// Ensure that we only unload source files, but not resource files.
if (this.sourceCodeStorage.ContainsFile(f)) {
LoggingService.Debug("Forms designer: Unloading file '" + f.FileName + "' because it no longer belongs to the designed form");
this.Files.Remove(f);
this.sourceCodeStorage.RemoveFile(f);
}
}
// Load all files which are new in the returned collection
foreach (OpenedFile f in sourceFiles.Except(this.Files).ToArray()) {
this.sourceCodeStorage.AddFile(f);
this.Files.Add(f);
}
LoggingService.Debug("Forms designer: Reloading designer because of LoadInternal on DesignerCodeFile");
this.sourceCodeStorage.DesignerCodeFile = newDesignerCodeFile;
this.UnloadDesigner();
this.designerCodeFileEncoding = ParserService.DefaultFileEncoding;
this.designerCodeFileDocument = new DocumentFactory().CreateDocument();
this.designerCodeFileDocument.TextContent = FileReader.ReadFileContent(stream, ref this.designerCodeFileEncoding);
this.LoadAndDisplayDesigner();
} finally {
this.inMasterLoadOperation = false;
}
} else {
// Loading a resource file
@ -224,14 +235,20 @@ namespace ICSharpCode.FormsDesigner @@ -224,14 +235,20 @@ namespace ICSharpCode.FormsDesigner
LoggingService.Debug("Forms designer: Reloading designer because of LoadInternal on resource file");
this.UnloadDesigner();
mustReload = true;
this.inMasterLoadOperation = true;
} else {
mustReload = false;
}
try {
LoggingService.Debug("Forms designer: Loading " + file.FileName + " in resource store");
this.resourceStore.Load(file, stream);
if (mustReload) {
this.LoadAndDisplayDesigner();
}
} finally {
this.inMasterLoadOperation = false;
}
}
}
@ -242,14 +259,8 @@ namespace ICSharpCode.FormsDesigner @@ -242,14 +259,8 @@ namespace ICSharpCode.FormsDesigner
if (hasUnmergedChanges) {
this.MergeFormChanges();
}
if (file == this.DesignerCodeFile) {
using(StreamWriter writer = new StreamWriter(stream, this.DesignerCodeFileEncoding)) {
writer.Write(this.DesignerCodeFileContent);
}
} else if (file == this.PrimaryFile) {
using(StreamWriter writer = new StreamWriter(stream, this.PrimaryFileEncoding)) {
writer.Write(this.PrimaryFileContent);
}
if (this.sourceCodeStorage.ContainsFile(file)) {
this.sourceCodeStorage.SaveFile(file, stream);
} else {
this.resourceStore.Save(file, stream);
}
@ -516,6 +527,7 @@ namespace ICSharpCode.FormsDesigner @@ -516,6 +527,7 @@ namespace ICSharpCode.FormsDesigner
void DesignerFlushed(object sender, EventArgs e)
{
this.resourceStore.CommitAllResourceChanges();
this.hasUnmergedChanges = false;
}
static string FormatLoadErrors(DesignSurface designSurface)
@ -530,8 +542,11 @@ namespace ICSharpCode.FormsDesigner @@ -530,8 +542,11 @@ namespace ICSharpCode.FormsDesigner
public virtual void MergeFormChanges()
{
if (this.HasLoadError) {
if (this.HasLoadError || this.designSurface == null) {
LoggingService.Debug("Forms designer: Cannot merge form changes because the designer is not loaded successfully or not loaded at all");
return;
} else if (this.DesignerCodeFile == null) {
throw new InvalidOperationException("Cannot merge form changes without a designer code file.");
}
bool isDirty = this.DesignerCodeFile.IsDirty;
LoggingService.Info("Merging form changes...");
@ -816,7 +831,7 @@ namespace ICSharpCode.FormsDesigner @@ -816,7 +831,7 @@ namespace ICSharpCode.FormsDesigner
protected void ReloadDesignerFromMemory()
{
using(MemoryStream ms = new MemoryStream(this.DesignerCodeFileEncoding.GetBytes(this.DesignerCodeFileContent), false)) {
using(MemoryStream ms = new MemoryStream(this.sourceCodeStorage.GetFileEncoding(this.DesignerCodeFile).GetBytes(this.DesignerCodeFileContent), false)) {
this.Load(this.DesignerCodeFile, ms);
}
@ -829,7 +844,7 @@ namespace ICSharpCode.FormsDesigner @@ -829,7 +844,7 @@ namespace ICSharpCode.FormsDesigner
void FileServiceFileRemoving(object sender, FileCancelEventArgs e)
{
if (!e.Cancel && this.DesignerCodeFile != null) {
if (!e.Cancel) {
if (WorkbenchSingleton.InvokeRequired) {
WorkbenchSingleton.SafeThreadAsyncCall(this.CheckForDesignerCodeFileDeletion, e);
} else {
@ -840,27 +855,33 @@ namespace ICSharpCode.FormsDesigner @@ -840,27 +855,33 @@ namespace ICSharpCode.FormsDesigner
void CheckForDesignerCodeFileDeletion(FileCancelEventArgs e)
{
if (this.DesignerCodeFile == null || String.IsNullOrEmpty(this.DesignerCodeFile.FileName)) {
return;
}
OpenedFile file;
if ((!e.IsDirectory && FileUtility.IsEqualFileName(this.DesignerCodeFile.FileName, e.FileName)) ||
(e.IsDirectory && FileUtility.IsBaseDirectory(e.FileName, this.DesignerCodeFile.FileName))) {
if (e.IsDirectory) {
file = this.Files.SingleOrDefault(
f => FileUtility.IsBaseDirectory(e.FileName, f.FileName)
);
} else {
file = this.Files.SingleOrDefault(
f => FileUtility.IsEqualFileName(f.FileName, e.FileName)
);
}
LoggingService.Info("Forms designer: Handling deletion of open designer code file '" + this.DesignerCodeFile.FileName + "'");
if (file == null || file == this.PrimaryFile)
return;
// When our designer code file is deleted,
// unload the designer and remove the file from the
// file list so that the primary view is not closed
// because of this event.
LoggingService.Info("Forms designer: Handling deletion of open designer code file '" + file.FileName + "'");
if (file == this.sourceCodeStorage.DesignerCodeFile) {
this.UnloadDesigner();
this.Files.Remove(this.DesignerCodeFile);
this.designerCodeFile = null;
this.designerCodeFileDocument = null;
this.designerCodeFileEncoding = null;
this.sourceCodeStorage.DesignerCodeFile = null;
}
// When any of our designer code files is deleted,
// remove the file from the file list so that
// the primary view is not closed because of this event.
this.Files.Remove(file);
this.sourceCodeStorage.RemoveFile(file);
}
#region Design surface manager (static)

Loading…
Cancel
Save