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 @@ |
|||||||
|
#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 @@ |
|||||||
|
// <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 @@ |
|||||||
|
// <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 @@ |
|||||||
|
<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 @@ |
|||||||
|
<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 @@ |
|||||||
|
// <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 @@ |
|||||||
|
// <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