Browse Source
Add AbstractViewContentHandlingLoadErrors for easy handling of invalid files. git-svn-id: svn://svn.sharpdevelop.net/sharpdevelop/trunk@2572 1ccf3a8d-04fe-1044-b7c0-cef0b8235c61shortcuts
19 changed files with 547 additions and 26 deletions
@ -0,0 +1,16 @@
@@ -0,0 +1,16 @@
|
||||
#region Using directives
|
||||
|
||||
using System.Reflection; |
||||
using System.Runtime.CompilerServices; |
||||
using System.Runtime.InteropServices; |
||||
|
||||
#endregion
|
||||
|
||||
// General Information about an assembly is controlled through the following
|
||||
// set of attributes. Change these attribute values to modify the information
|
||||
// associated with an assembly.
|
||||
[assembly: AssemblyTitle("WpfDesign.AddIn")] |
||||
[assembly: AssemblyDescription("")] |
||||
[assembly: AssemblyConfiguration("")] |
||||
[assembly: AssemblyTrademark("")] |
||||
[assembly: AssemblyCulture("")] |
@ -0,0 +1,46 @@
@@ -0,0 +1,46 @@
|
||||
// <file>
|
||||
// <copyright see="prj:///doc/copyright.txt"/>
|
||||
// <license see="prj:///doc/license.txt"/>
|
||||
// <author name="Daniel Grunwald"/>
|
||||
// <version>$Revision$</version>
|
||||
// </file>
|
||||
|
||||
using System; |
||||
using System.IO; |
||||
using ICSharpCode.SharpDevelop; |
||||
using ICSharpCode.SharpDevelop.Gui; |
||||
|
||||
namespace ICSharpCode.WpfDesign.AddIn |
||||
{ |
||||
public class WpfPrimaryDisplayBinding : IDisplayBinding |
||||
{ |
||||
public bool CanCreateContentForFile(string fileName) |
||||
{ |
||||
return Path.GetExtension(fileName).Equals(".xaml", StringComparison.OrdinalIgnoreCase); |
||||
} |
||||
|
||||
public IViewContent CreateContentForFile(OpenedFile file) |
||||
{ |
||||
return new WpfViewContent(file); |
||||
} |
||||
} |
||||
|
||||
public class WpfSecondaryDisplayBinding : ISecondaryDisplayBinding |
||||
{ |
||||
public bool ReattachWhenParserServiceIsReady { |
||||
get { |
||||
return false; |
||||
} |
||||
} |
||||
|
||||
public bool CanAttachTo(IViewContent content) |
||||
{ |
||||
return Path.GetExtension(content.PrimaryFileName).Equals(".xaml", StringComparison.OrdinalIgnoreCase); |
||||
} |
||||
|
||||
public IViewContent[] CreateSecondaryViewContent(IViewContent viewContent) |
||||
{ |
||||
return new IViewContent[] { new WpfViewContent(viewContent.PrimaryFile) }; |
||||
} |
||||
} |
||||
} |
@ -0,0 +1,53 @@
@@ -0,0 +1,53 @@
|
||||
// <file>
|
||||
// <copyright see="prj:///doc/copyright.txt"/>
|
||||
// <license see="prj:///doc/license.txt"/>
|
||||
// <author name="Daniel Grunwald"/>
|
||||
// <version>$Revision$</version>
|
||||
// </file>
|
||||
|
||||
using System; |
||||
using System.Text; |
||||
using System.Xml; |
||||
using ICSharpCode.SharpDevelop; |
||||
using ICSharpCode.SharpDevelop.Gui; |
||||
using System.Windows.Forms; |
||||
using System.Windows.Forms.Integration; |
||||
using ICSharpCode.WpfDesign.Designer; |
||||
|
||||
namespace ICSharpCode.WpfDesign.AddIn |
||||
{ |
||||
/// <summary>
|
||||
/// Description of WpfViewContent.
|
||||
/// </summary>
|
||||
public class WpfViewContent : AbstractViewContentHandlingLoadErrors |
||||
{ |
||||
ElementHost wpfHost; |
||||
DesignSurface designer; |
||||
|
||||
public WpfViewContent(OpenedFile file) : base(file) |
||||
{ |
||||
} |
||||
|
||||
protected override void LoadInternal(OpenedFile file, System.IO.Stream stream) |
||||
{ |
||||
if (designer == null) { |
||||
// initialize designer on first load
|
||||
wpfHost = new ElementHost(); |
||||
designer = new DesignSurface(); |
||||
wpfHost.Child = designer; |
||||
this.UserControl = wpfHost; |
||||
} |
||||
using (XmlTextReader r = new XmlTextReader(stream)) { |
||||
designer.LoadDesigner(r); |
||||
} |
||||
} |
||||
|
||||
protected override void SaveInternal(OpenedFile file, System.IO.Stream stream) |
||||
{ |
||||
using (XmlTextWriter xmlWriter = new XmlTextWriter(stream, Encoding.UTF8)) { |
||||
xmlWriter.Formatting = Formatting.Indented; |
||||
designer.SaveDesigner(xmlWriter); |
||||
} |
||||
} |
||||
} |
||||
} |
@ -0,0 +1,80 @@
@@ -0,0 +1,80 @@
|
||||
<Project DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003"> |
||||
<PropertyGroup> |
||||
<ProjectGuid>{9A9D6FD4-6A2E-455D-ACC3-DDA775FE9865}</ProjectGuid> |
||||
<Configuration Condition=" '$(Configuration)' == '' ">Debug</Configuration> |
||||
<Platform Condition=" '$(Platform)' == '' ">AnyCPU</Platform> |
||||
<OutputType>Library</OutputType> |
||||
<RootNamespace>ICSharpCode.WpfDesign.AddIn</RootNamespace> |
||||
<AssemblyName>ICSharpCode.WpfDesign.AddIn</AssemblyName> |
||||
<OutputPath>..\..\..\..\..\AddIns\AddIns\DisplayBindings\WpfDesign\</OutputPath> |
||||
<AllowUnsafeBlocks>False</AllowUnsafeBlocks> |
||||
<NoStdLib>False</NoStdLib> |
||||
<WarningLevel>4</WarningLevel> |
||||
<TreatWarningsAsErrors>false</TreatWarningsAsErrors> |
||||
</PropertyGroup> |
||||
<PropertyGroup Condition=" '$(Configuration)' == 'Debug' "> |
||||
<DebugSymbols>true</DebugSymbols> |
||||
<DebugType>Full</DebugType> |
||||
<CheckForOverflowUnderflow>True</CheckForOverflowUnderflow> |
||||
<DefineConstants>DEBUG;TRACE</DefineConstants> |
||||
<Optimize>False</Optimize> |
||||
</PropertyGroup> |
||||
<PropertyGroup Condition=" '$(Configuration)' == 'Release' "> |
||||
<DebugSymbols>False</DebugSymbols> |
||||
<DebugType>None</DebugType> |
||||
<CheckForOverflowUnderflow>False</CheckForOverflowUnderflow> |
||||
<DefineConstants>TRACE</DefineConstants> |
||||
</PropertyGroup> |
||||
<PropertyGroup Condition=" '$(Platform)' == 'AnyCPU' "> |
||||
<RegisterForComInterop>False</RegisterForComInterop> |
||||
<GenerateSerializationAssemblies>Auto</GenerateSerializationAssemblies> |
||||
<BaseAddress>4194304</BaseAddress> |
||||
<PlatformTarget>AnyCPU</PlatformTarget> |
||||
<FileAlignment>4096</FileAlignment> |
||||
</PropertyGroup> |
||||
<Import Project="$(MSBuildBinPath)\Microsoft.CSharp.Targets" /> |
||||
<ItemGroup> |
||||
<Reference Include="PresentationCore" /> |
||||
<Reference Include="PresentationFramework" /> |
||||
<Reference Include="System" /> |
||||
<Reference Include="System.Data" /> |
||||
<Reference Include="System.Drawing" /> |
||||
<Reference Include="System.Windows.Forms" /> |
||||
<Reference Include="System.Xml" /> |
||||
<Reference Include="WindowsBase" /> |
||||
<Reference Include="WindowsFormsIntegration" /> |
||||
</ItemGroup> |
||||
<ItemGroup> |
||||
<None Include="WpfDesign.addin"> |
||||
<CopyToOutputDirectory>Always</CopyToOutputDirectory> |
||||
</None> |
||||
<Compile Include="..\..\..\..\Main\GlobalAssemblyInfo.cs"> |
||||
<Link>Configuration\GlobalAssemblyInfo.cs</Link> |
||||
</Compile> |
||||
<Compile Include="Configuration\AssemblyInfo.cs" /> |
||||
<Compile Include="Src\WpfDisplayBinding.cs" /> |
||||
<Compile Include="Src\WpfViewContent.cs" /> |
||||
</ItemGroup> |
||||
<ItemGroup> |
||||
<ProjectReference Include="..\..\..\..\Main\Base\Project\ICSharpCode.SharpDevelop.csproj"> |
||||
<Project>{2748AD25-9C63-4E12-877B-4DCE96FBED54}</Project> |
||||
<Name>ICSharpCode.SharpDevelop</Name> |
||||
<Private>False</Private> |
||||
</ProjectReference> |
||||
<ProjectReference Include="..\..\..\..\Main\Core\Project\ICSharpCode.Core.csproj"> |
||||
<Project>{35CEF10F-2D4C-45F2-9DD1-161E0FEC583C}</Project> |
||||
<Name>ICSharpCode.Core</Name> |
||||
<Private>False</Private> |
||||
</ProjectReference> |
||||
<ProjectReference Include="..\WpfDesign.Designer\Project\WpfDesign.Designer.csproj"> |
||||
<Project>{78CC29AC-CC79-4355-B1F2-97936DF198AC}</Project> |
||||
<Name>WpfDesign.Designer</Name> |
||||
<Private>False</Private> |
||||
</ProjectReference> |
||||
<ProjectReference Include="..\WpfDesign\Project\WpfDesign.csproj"> |
||||
<Project>{66A378A1-E9F4-4AD5-8946-D0EC06C2902F}</Project> |
||||
<Name>WpfDesign</Name> |
||||
<Private>False</Private> |
||||
</ProjectReference> |
||||
</ItemGroup> |
||||
</Project> |
@ -0,0 +1,21 @@
@@ -0,0 +1,21 @@
|
||||
<AddIn name = "WPF Designer AddIn" |
||||
author = "Daniel Grunwald" |
||||
copyright = "prj:///doc/copyright.txt" |
||||
description = "WPF Designer"> |
||||
|
||||
<Runtime> |
||||
<Import assembly = "ICSharpCode.WpfDesign.AddIn.dll"/> |
||||
</Runtime> |
||||
|
||||
<Path name = "/SharpDevelop/Workbench/DisplayBindings"> |
||||
<!--<DisplayBinding id = "WPFDesigner" |
||||
class = "ICSharpCode.WpfDesign.AddIn.WpfPrimaryDisplayBinding" |
||||
insertbefore = "Text" |
||||
fileNamePattern = "\.xaml$" |
||||
title = "WPF designer"/>--> |
||||
<DisplayBinding id = "WPFDesigner" |
||||
type = "Secondary" |
||||
class = "ICSharpCode.WpfDesign.AddIn.WpfSecondaryDisplayBinding" |
||||
fileNamePattern = "\.xaml$"/> |
||||
</Path> |
||||
</AddIn> |
@ -0,0 +1,138 @@
@@ -0,0 +1,138 @@
|
||||
// <file>
|
||||
// <copyright see="prj:///doc/copyright.txt"/>
|
||||
// <license see="prj:///doc/license.txt"/>
|
||||
// <author name="Daniel Grunwald"/>
|
||||
// <version>$Revision$</version>
|
||||
// </file>
|
||||
|
||||
using System; |
||||
using System.Collections.Generic; |
||||
using System.Drawing; |
||||
using System.IO; |
||||
using System.Windows.Forms; |
||||
|
||||
namespace ICSharpCode.SharpDevelop.Gui |
||||
{ |
||||
/// <summary>
|
||||
/// This class handles errors in the Load method and prevents destroying invalid files.
|
||||
/// Scenario:
|
||||
/// open a .resx file both with the resource editor and the text editor. Add a string entry using the
|
||||
/// resource editor. Modify it using the text editor, and introduce invalid XML syntax (e.g. use a
|
||||
/// < in the edited value. Close the text editor without saving the changes. The resource editor
|
||||
/// will show the load error. Close the resource editor, this time saving the changes.
|
||||
/// The resource editor is now expected to write the invalid file to disk.
|
||||
/// This class handles this scenario by displaying an error message for invalid files, and
|
||||
/// holding the invalid data that got copied from the text editor to the resource editor in memory.
|
||||
/// So saving during a load error works as expected.
|
||||
/// </summary>
|
||||
public abstract class AbstractViewContentHandlingLoadErrors : AbstractViewContent |
||||
{ |
||||
Panel panel = new Panel(); |
||||
Control userControl; |
||||
|
||||
protected AbstractViewContentHandlingLoadErrors() |
||||
{ |
||||
} |
||||
|
||||
protected AbstractViewContentHandlingLoadErrors(OpenedFile file) : base(file) |
||||
{ |
||||
} |
||||
|
||||
public sealed override Control Control { |
||||
get { return panel; } |
||||
} |
||||
|
||||
protected Control UserControl { |
||||
get { return userControl; } |
||||
set { |
||||
if (userControl != value) { |
||||
if (errorList.Count == 0 && userControl != null) { |
||||
panel.Controls.Remove(userControl); |
||||
} |
||||
userControl = value; |
||||
userControl.Dock = DockStyle.Fill; |
||||
if (errorList.Count == 0 && userControl != null) { |
||||
panel.Controls.Add(userControl); |
||||
} |
||||
} |
||||
} |
||||
} |
||||
|
||||
public bool HasLoadError { |
||||
get { |
||||
return errorList.Count > 0; |
||||
} |
||||
} |
||||
|
||||
class LoadError |
||||
{ |
||||
internal Exception exception; |
||||
internal byte[] fileData; |
||||
|
||||
public LoadError(Exception exception, Stream stream) |
||||
{ |
||||
this.exception = exception; |
||||
stream.Position = 0; |
||||
this.fileData = new byte[(int)stream.Length]; |
||||
int pos = 0; |
||||
while (pos < fileData.Length) { |
||||
int c = stream.Read(fileData, pos, fileData.Length - pos); |
||||
if (c == 0) break; |
||||
pos += c; |
||||
} |
||||
} |
||||
} |
||||
|
||||
TextBox errorTextBox; |
||||
|
||||
void ShowError(Exception ex) |
||||
{ |
||||
if (errorTextBox == null) { |
||||
errorTextBox = new TextBox(); |
||||
errorTextBox.Multiline = true; |
||||
errorTextBox.ReadOnly = true; |
||||
errorTextBox.BackColor = SystemColors.Window; |
||||
errorTextBox.Dock = DockStyle.Fill; |
||||
} |
||||
errorTextBox.Text = ex.ToString(); |
||||
panel.Controls.Clear(); |
||||
panel.Controls.Add(errorTextBox); |
||||
} |
||||
|
||||
Dictionary<OpenedFile, LoadError> errorList = new Dictionary<OpenedFile, LoadError>(); |
||||
|
||||
public override sealed void Load(OpenedFile file, Stream stream) |
||||
{ |
||||
try { |
||||
LoadInternal(file, new UnclosableStream(stream)); |
||||
if (errorList.Count > 0) { |
||||
errorList.Remove(file); |
||||
if (errorList.Count == 0) { |
||||
panel.Controls.Clear(); |
||||
if (userControl != null) { |
||||
panel.Controls.Add(userControl); |
||||
} |
||||
} else { |
||||
ShowError(Linq.First(errorList.Values).exception); |
||||
} |
||||
} |
||||
} catch (Exception ex) { |
||||
errorList[file] = new LoadError(ex, stream); |
||||
ShowError(ex); |
||||
} |
||||
} |
||||
|
||||
public override sealed void Save(OpenedFile file, Stream stream) |
||||
{ |
||||
if (errorList.ContainsKey(file)) { |
||||
byte[] data = errorList[file].fileData; |
||||
stream.Write(data, 0, data.Length); |
||||
} else { |
||||
SaveInternal(file, stream); |
||||
} |
||||
} |
||||
|
||||
protected abstract void LoadInternal(OpenedFile file, Stream stream); |
||||
protected abstract void SaveInternal(OpenedFile file, Stream stream); |
||||
} |
||||
} |
@ -0,0 +1,117 @@
@@ -0,0 +1,117 @@
|
||||
// <file>
|
||||
// <copyright see="prj:///doc/copyright.txt"/>
|
||||
// <license see="prj:///doc/license.txt"/>
|
||||
// <author name="Daniel Grunwald"/>
|
||||
// <version>$Revision$</version>
|
||||
// </file>
|
||||
|
||||
using System; |
||||
using System.IO; |
||||
|
||||
namespace ICSharpCode.SharpDevelop |
||||
{ |
||||
/// <summary>
|
||||
/// Wraps another stream. Closing this stream does not close the base stream.
|
||||
/// </summary>
|
||||
public class UnclosableStream : Stream |
||||
{ |
||||
Stream baseStream; |
||||
|
||||
public UnclosableStream(Stream baseStream) |
||||
{ |
||||
if (baseStream == null) |
||||
throw new ArgumentNullException("baseStream"); |
||||
this.baseStream = baseStream; |
||||
} |
||||
|
||||
public override bool CanRead { |
||||
get { return baseStream.CanRead; } |
||||
} |
||||
|
||||
public override bool CanSeek { |
||||
get { return baseStream.CanSeek; } |
||||
} |
||||
|
||||
public override bool CanWrite { |
||||
get { return baseStream.CanWrite; } |
||||
} |
||||
|
||||
public override long Length { |
||||
get { return baseStream.Length; } |
||||
} |
||||
|
||||
public override long Position { |
||||
get { return baseStream.Position; } |
||||
set { baseStream.Position = value; } |
||||
} |
||||
|
||||
public override void Flush() |
||||
{ |
||||
baseStream.Flush(); |
||||
} |
||||
|
||||
public override long Seek(long offset, SeekOrigin origin) |
||||
{ |
||||
return baseStream.Seek(offset, origin); |
||||
} |
||||
|
||||
public override void SetLength(long value) |
||||
{ |
||||
baseStream.SetLength(value); |
||||
} |
||||
|
||||
public override int Read(byte[] buffer, int offset, int count) |
||||
{ |
||||
return baseStream.Read(buffer, offset, count); |
||||
} |
||||
|
||||
public override void Write(byte[] buffer, int offset, int count) |
||||
{ |
||||
baseStream.Write(buffer, offset, count); |
||||
} |
||||
|
||||
public override IAsyncResult BeginRead(byte[] buffer, int offset, int count, AsyncCallback callback, object state) |
||||
{ |
||||
return baseStream.BeginRead(buffer, offset, count, callback, state); |
||||
} |
||||
|
||||
public override IAsyncResult BeginWrite(byte[] buffer, int offset, int count, AsyncCallback callback, object state) |
||||
{ |
||||
return baseStream.BeginWrite(buffer, offset, count, callback, state); |
||||
} |
||||
|
||||
public override bool CanTimeout { |
||||
get { return baseStream.CanTimeout; } |
||||
} |
||||
|
||||
public override int EndRead(IAsyncResult asyncResult) |
||||
{ |
||||
return baseStream.EndRead(asyncResult); |
||||
} |
||||
|
||||
public override void EndWrite(IAsyncResult asyncResult) |
||||
{ |
||||
baseStream.EndWrite(asyncResult); |
||||
} |
||||
|
||||
public override int ReadByte() |
||||
{ |
||||
return baseStream.ReadByte(); |
||||
} |
||||
|
||||
public override int ReadTimeout { |
||||
get { return baseStream.ReadTimeout; } |
||||
set { baseStream.ReadTimeout = value; } |
||||
} |
||||
|
||||
public override void WriteByte(byte value) |
||||
{ |
||||
baseStream.WriteByte(value); |
||||
} |
||||
|
||||
public override int WriteTimeout { |
||||
get { return baseStream.WriteTimeout; } |
||||
set { baseStream.WriteTimeout = value; } |
||||
} |
||||
} |
||||
} |
Loading…
Reference in new issue