9 changed files with 447 additions and 0 deletions
@ -0,0 +1,31 @@ |
|||||||
|
#region Using directives
|
||||||
|
|
||||||
|
using System; |
||||||
|
using System.Reflection; |
||||||
|
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("EmbeddedImageAddIn")] |
||||||
|
[assembly: AssemblyDescription("")] |
||||||
|
[assembly: AssemblyConfiguration("")] |
||||||
|
[assembly: AssemblyCompany("")] |
||||||
|
[assembly: AssemblyProduct("EmbeddedImageAddIn")] |
||||||
|
[assembly: AssemblyCopyright("Copyright 2010")] |
||||||
|
[assembly: AssemblyTrademark("")] |
||||||
|
[assembly: AssemblyCulture("")] |
||||||
|
|
||||||
|
// This sets the default COM visibility of types in the assembly to invisible.
|
||||||
|
// If you need to expose a type to COM, use [ComVisible(true)] on that type.
|
||||||
|
[assembly: ComVisible(false)] |
||||||
|
|
||||||
|
// The assembly version has following format :
|
||||||
|
//
|
||||||
|
// Major.Minor.Build.Revision
|
||||||
|
//
|
||||||
|
// You can specify all the values or you can use the default the Revision and
|
||||||
|
// Build Numbers by using the '*' as shown below:
|
||||||
|
[assembly: AssemblyVersion("1.0.*")] |
@ -0,0 +1,20 @@ |
|||||||
|
<AddIn name = "EmbeddedImageAddIn" |
||||||
|
author = "Daniel Grunwald" |
||||||
|
description = "Allows embedding images in source code comments"> |
||||||
|
|
||||||
|
<Manifest> |
||||||
|
<Identity name = "SharpDevelop.Samples.EmbeddedImageAddIn"/> |
||||||
|
</Manifest> |
||||||
|
|
||||||
|
<Runtime> |
||||||
|
<Import assembly = "EmbeddedImageAddIn.dll"/> |
||||||
|
</Runtime> |
||||||
|
|
||||||
|
<Path name="/SharpDevelop/Workbench/LanguageBindings"> |
||||||
|
<Class id="EmbeddedImage" class="EmbeddedImageAddIn.EmbeddedImageLanguageBinding"/> |
||||||
|
</Path> |
||||||
|
|
||||||
|
<Path name="/SharpDevelop/Workbench/MainMenu/Edit/Insert"> |
||||||
|
<MenuItem id="EmbeddedImage" class="EmbeddedImageAddIn.InsertImageCommand" label="Insert Image..."/> |
||||||
|
</Path> |
||||||
|
</AddIn> |
@ -0,0 +1,80 @@ |
|||||||
|
<?xml version="1.0" encoding="utf-8"?> |
||||||
|
<Project ToolsVersion="4.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003" DefaultTargets="Build"> |
||||||
|
<PropertyGroup> |
||||||
|
<ProjectGuid>{1F60F9B0-E2FE-462F-9758-2E834D845438}</ProjectGuid> |
||||||
|
<Configuration Condition=" '$(Configuration)' == '' ">Debug</Configuration> |
||||||
|
<Platform Condition=" '$(Platform)' == '' ">x86</Platform> |
||||||
|
<OutputType>Library</OutputType> |
||||||
|
<RootNamespace>EmbeddedImageAddIn</RootNamespace> |
||||||
|
<AssemblyName>EmbeddedImageAddIn</AssemblyName> |
||||||
|
<TargetFrameworkVersion>v4.0</TargetFrameworkVersion> |
||||||
|
<OutputPath>..\..\AddIns\Samples\EmbeddedImage\</OutputPath> |
||||||
|
<AllowUnsafeBlocks>False</AllowUnsafeBlocks> |
||||||
|
<NoStdLib>False</NoStdLib> |
||||||
|
<WarningLevel>4</WarningLevel> |
||||||
|
<TreatWarningsAsErrors>false</TreatWarningsAsErrors> |
||||||
|
</PropertyGroup> |
||||||
|
<PropertyGroup Condition=" '$(Platform)' == 'x86' "> |
||||||
|
<PlatformTarget>x86</PlatformTarget> |
||||||
|
<RegisterForComInterop>False</RegisterForComInterop> |
||||||
|
<GenerateSerializationAssemblies>Auto</GenerateSerializationAssemblies> |
||||||
|
<BaseAddress>4194304</BaseAddress> |
||||||
|
<FileAlignment>4096</FileAlignment> |
||||||
|
</PropertyGroup> |
||||||
|
<PropertyGroup Condition=" '$(Configuration)' == 'Debug' "> |
||||||
|
<DebugSymbols>true</DebugSymbols> |
||||||
|
<DebugType>Full</DebugType> |
||||||
|
<Optimize>False</Optimize> |
||||||
|
<CheckForOverflowUnderflow>True</CheckForOverflowUnderflow> |
||||||
|
<DefineConstants>DEBUG;TRACE</DefineConstants> |
||||||
|
</PropertyGroup> |
||||||
|
<PropertyGroup Condition=" '$(Configuration)' == 'Release' "> |
||||||
|
<DebugSymbols>False</DebugSymbols> |
||||||
|
<DebugType>None</DebugType> |
||||||
|
<Optimize>True</Optimize> |
||||||
|
<CheckForOverflowUnderflow>False</CheckForOverflowUnderflow> |
||||||
|
<DefineConstants>TRACE</DefineConstants> |
||||||
|
</PropertyGroup> |
||||||
|
<ItemGroup> |
||||||
|
<Reference Include="ICSharpCode.AvalonEdit"> |
||||||
|
<HintPath>..\..\bin\ICSharpCode.AvalonEdit.dll</HintPath> |
||||||
|
<Private>False</Private> |
||||||
|
</Reference> |
||||||
|
<Reference Include="ICSharpCode.Core"> |
||||||
|
<HintPath>..\..\bin\ICSharpCode.Core.dll</HintPath> |
||||||
|
<Private>False</Private> |
||||||
|
</Reference> |
||||||
|
<Reference Include="ICSharpCode.SharpDevelop"> |
||||||
|
<HintPath>..\..\bin\ICSharpCode.SharpDevelop.dll</HintPath> |
||||||
|
<Private>False</Private> |
||||||
|
</Reference> |
||||||
|
<Reference Include="PresentationCore" /> |
||||||
|
<Reference Include="PresentationFramework" /> |
||||||
|
<Reference Include="System" /> |
||||||
|
<Reference Include="System.Core"> |
||||||
|
<RequiredTargetFramework>3.5</RequiredTargetFramework> |
||||||
|
</Reference> |
||||||
|
<Reference Include="System.Drawing" /> |
||||||
|
<Reference Include="System.Windows.Forms" /> |
||||||
|
<Reference Include="System.Xaml" /> |
||||||
|
<Reference Include="System.Xml" /> |
||||||
|
<Reference Include="System.Xml.Linq"> |
||||||
|
<RequiredTargetFramework>3.5</RequiredTargetFramework> |
||||||
|
</Reference> |
||||||
|
<Reference Include="WindowsBase" /> |
||||||
|
</ItemGroup> |
||||||
|
<ItemGroup> |
||||||
|
<None Include="EmbeddedImageAddIn.addin"> |
||||||
|
<CopyToOutputDirectory>Always</CopyToOutputDirectory> |
||||||
|
</None> |
||||||
|
</ItemGroup> |
||||||
|
<ItemGroup> |
||||||
|
<Compile Include="Configuration\AssemblyInfo.cs" /> |
||||||
|
<Compile Include="EmbeddedImageLanguageBinding.cs" /> |
||||||
|
<Compile Include="ImageCache.cs" /> |
||||||
|
<Compile Include="ImageElement.cs" /> |
||||||
|
<Compile Include="ImageElementGenerator.cs" /> |
||||||
|
<Compile Include="InsertImageCommand.cs" /> |
||||||
|
</ItemGroup> |
||||||
|
<Import Project="$(MSBuildBinPath)\Microsoft.CSharp.Targets" /> |
||||||
|
</Project> |
@ -0,0 +1,18 @@ |
|||||||
|
|
||||||
|
Microsoft Visual Studio Solution File, Format Version 11.00 |
||||||
|
# Visual Studio 2010 |
||||||
|
# SharpDevelop 4.0.0.7002 |
||||||
|
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "EmbeddedImageAddIn", "EmbeddedImageAddIn.csproj", "{1F60F9B0-E2FE-462F-9758-2E834D845438}" |
||||||
|
EndProject |
||||||
|
Global |
||||||
|
GlobalSection(SolutionConfigurationPlatforms) = preSolution |
||||||
|
Debug|x86 = Debug|x86 |
||||||
|
Release|x86 = Release|x86 |
||||||
|
EndGlobalSection |
||||||
|
GlobalSection(ProjectConfigurationPlatforms) = postSolution |
||||||
|
{1F60F9B0-E2FE-462F-9758-2E834D845438}.Debug|x86.Build.0 = Debug|x86 |
||||||
|
{1F60F9B0-E2FE-462F-9758-2E834D845438}.Debug|x86.ActiveCfg = Debug|x86 |
||||||
|
{1F60F9B0-E2FE-462F-9758-2E834D845438}.Release|x86.Build.0 = Release|x86 |
||||||
|
{1F60F9B0-E2FE-462F-9758-2E834D845438}.Release|x86.ActiveCfg = Release|x86 |
||||||
|
EndGlobalSection |
||||||
|
EndGlobal |
@ -0,0 +1,38 @@ |
|||||||
|
// Copyright (c) AlphaSierraPapa for the SharpDevelop Team (for details please see \doc\copyright.txt)
|
||||||
|
// This code is distributed under MIT X11 license (for details please see \doc\license.txt)
|
||||||
|
|
||||||
|
using System; |
||||||
|
using System.IO; |
||||||
|
using ICSharpCode.AvalonEdit.Rendering; |
||||||
|
using ICSharpCode.SharpDevelop; |
||||||
|
using ICSharpCode.SharpDevelop.Editor; |
||||||
|
|
||||||
|
namespace EmbeddedImageAddIn |
||||||
|
{ |
||||||
|
// SharpDevelop creates one instance of EmbeddedImageLanguageBinding for each text editor.
|
||||||
|
public class EmbeddedImageLanguageBinding : DefaultLanguageBinding |
||||||
|
{ |
||||||
|
TextView textView; |
||||||
|
ImageElementGenerator g; |
||||||
|
|
||||||
|
public override void Attach(ITextEditor editor) |
||||||
|
{ |
||||||
|
base.Attach(editor); |
||||||
|
// ITextEditor is SharpDevelop's abstraction of the text editor.
|
||||||
|
// We use GetService() to get the underlying AvalonEdit instance.
|
||||||
|
textView = editor.GetService(typeof(TextView)) as TextView; |
||||||
|
if (textView != null) { |
||||||
|
g = new ImageElementGenerator(Path.GetDirectoryName(editor.FileName)); |
||||||
|
textView.ElementGenerators.Add(g); |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
public override void Detach() |
||||||
|
{ |
||||||
|
if (textView != null) { |
||||||
|
textView.ElementGenerators.Remove(g); |
||||||
|
} |
||||||
|
base.Detach(); |
||||||
|
} |
||||||
|
} |
||||||
|
} |
@ -0,0 +1,58 @@ |
|||||||
|
// Copyright (c) AlphaSierraPapa for the SharpDevelop Team (for details please see \doc\copyright.txt)
|
||||||
|
// This code is distributed under MIT X11 license (for details please see \doc\license.txt)
|
||||||
|
|
||||||
|
using System; |
||||||
|
using System.Collections.Generic; |
||||||
|
using System.IO; |
||||||
|
using System.Linq; |
||||||
|
using System.Windows.Media; |
||||||
|
using System.Windows.Media.Imaging; |
||||||
|
|
||||||
|
using ICSharpCode.Core; |
||||||
|
|
||||||
|
namespace EmbeddedImageAddIn |
||||||
|
{ |
||||||
|
public static class ImageCache |
||||||
|
{ |
||||||
|
static readonly Dictionary<FileName, WeakReference> imageCache = new Dictionary<FileName, WeakReference>(); |
||||||
|
|
||||||
|
public static ImageSource GetImage(FileName fileName) |
||||||
|
{ |
||||||
|
lock (imageCache) { |
||||||
|
WeakReference wr; |
||||||
|
ImageSource image; |
||||||
|
// retrieve image from cache, if possible
|
||||||
|
if (imageCache.TryGetValue(fileName, out wr)) { |
||||||
|
image = (ImageSource)wr.Target; |
||||||
|
if (image != null) |
||||||
|
return image; |
||||||
|
} |
||||||
|
// load image:
|
||||||
|
image = LoadBitmap(fileName); |
||||||
|
if (image != null) |
||||||
|
imageCache[fileName] = new WeakReference(image); |
||||||
|
// clean up cache:
|
||||||
|
List<FileName> entriesToRemove = (from p in imageCache where !p.Value.IsAlive select p.Key).ToList(); |
||||||
|
foreach (var entry in entriesToRemove) |
||||||
|
imageCache.Remove(entry); |
||||||
|
return image; |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
static BitmapImage LoadBitmap(string fileName) |
||||||
|
{ |
||||||
|
try { |
||||||
|
if (File.Exists(fileName)) { |
||||||
|
BitmapImage bitmap = new BitmapImage(new Uri(fileName)); |
||||||
|
bitmap.Freeze(); |
||||||
|
return bitmap; |
||||||
|
} |
||||||
|
} catch (ArgumentException) { |
||||||
|
// invalid filename syntax
|
||||||
|
} catch (IOException) { |
||||||
|
// other IO error
|
||||||
|
} |
||||||
|
return null; |
||||||
|
} |
||||||
|
} |
||||||
|
} |
@ -0,0 +1,101 @@ |
|||||||
|
// Copyright (c) AlphaSierraPapa for the SharpDevelop Team (for details please see \doc\copyright.txt)
|
||||||
|
// This code is distributed under MIT X11 license (for details please see \doc\license.txt)
|
||||||
|
|
||||||
|
using System; |
||||||
|
using System.Diagnostics; |
||||||
|
using System.Windows; |
||||||
|
using System.Windows.Input; |
||||||
|
using System.Windows.Media; |
||||||
|
using System.Windows.Media.TextFormatting; |
||||||
|
using ICSharpCode.AvalonEdit.Rendering; |
||||||
|
|
||||||
|
namespace EmbeddedImageAddIn |
||||||
|
{ |
||||||
|
/// <summary>
|
||||||
|
/// VisualLineElement implementation for embedded images.
|
||||||
|
/// </summary>
|
||||||
|
public class ImageElement : VisualLineElement |
||||||
|
{ |
||||||
|
readonly string imageFileName; |
||||||
|
readonly ImageSource image; |
||||||
|
|
||||||
|
public ImageElement(string imageFileName, ImageSource image, int documentLength) : base(1, documentLength) |
||||||
|
{ |
||||||
|
if (imageFileName == null) |
||||||
|
throw new ArgumentNullException("imageFileName"); |
||||||
|
if (image == null) |
||||||
|
throw new ArgumentNullException("image"); |
||||||
|
this.imageFileName = imageFileName; |
||||||
|
this.image = image; |
||||||
|
} |
||||||
|
|
||||||
|
public override TextRun CreateTextRun(int startVisualColumn, ITextRunConstructionContext context) |
||||||
|
{ |
||||||
|
return new ImageTextRun(image, this.TextRunProperties); |
||||||
|
} |
||||||
|
|
||||||
|
protected override void OnMouseDown(MouseButtonEventArgs e) |
||||||
|
{ |
||||||
|
base.OnMouseDown(e); |
||||||
|
if (!e.Handled && e.ClickCount == 2) { |
||||||
|
// double click on image: open the image in editor
|
||||||
|
try { |
||||||
|
Process.Start(imageFileName); |
||||||
|
} catch (Exception ex) { |
||||||
|
MessageBox.Show(ex.Message); |
||||||
|
} |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
sealed class ImageTextRun : TextEmbeddedObject |
||||||
|
{ |
||||||
|
readonly ImageSource image; |
||||||
|
readonly TextRunProperties properties; |
||||||
|
|
||||||
|
public ImageTextRun(ImageSource image, TextRunProperties properties) |
||||||
|
{ |
||||||
|
this.image = image; |
||||||
|
this.properties = properties; |
||||||
|
} |
||||||
|
|
||||||
|
public override LineBreakCondition BreakBefore { |
||||||
|
get { return LineBreakCondition.BreakPossible; } |
||||||
|
} |
||||||
|
|
||||||
|
public override LineBreakCondition BreakAfter { |
||||||
|
get { return LineBreakCondition.BreakPossible; } |
||||||
|
} |
||||||
|
|
||||||
|
public override bool HasFixedSize { |
||||||
|
get { return true; } |
||||||
|
} |
||||||
|
|
||||||
|
public override CharacterBufferReference CharacterBufferReference { |
||||||
|
get { return new CharacterBufferReference(); } |
||||||
|
} |
||||||
|
|
||||||
|
public override int Length { |
||||||
|
get { return 1; } |
||||||
|
} |
||||||
|
|
||||||
|
public override TextRunProperties Properties { |
||||||
|
get { return properties; } |
||||||
|
} |
||||||
|
|
||||||
|
public override TextEmbeddedObjectMetrics Format(double remainingParagraphWidth) |
||||||
|
{ |
||||||
|
return new TextEmbeddedObjectMetrics(image.Width, image.Height, image.Height); |
||||||
|
} |
||||||
|
|
||||||
|
public override Rect ComputeBoundingBox(bool rightToLeft, bool sideways) |
||||||
|
{ |
||||||
|
return new Rect(0, 0, image.Width, image.Height); |
||||||
|
} |
||||||
|
|
||||||
|
public override void Draw(DrawingContext drawingContext, Point origin, bool rightToLeft, bool sideways) |
||||||
|
{ |
||||||
|
drawingContext.DrawImage(image, new Rect(origin.X, origin.Y - image.Height, image.Width, image.Height)); |
||||||
|
} |
||||||
|
} |
||||||
|
} |
||||||
|
} |
@ -0,0 +1,62 @@ |
|||||||
|
// Copyright (c) AlphaSierraPapa for the SharpDevelop Team (for details please see \doc\copyright.txt)
|
||||||
|
// This code is distributed under MIT X11 license (for details please see \doc\license.txt)
|
||||||
|
|
||||||
|
using System; |
||||||
|
using System.IO; |
||||||
|
using System.Text.RegularExpressions; |
||||||
|
using System.Windows.Media; |
||||||
|
using ICSharpCode.AvalonEdit.Document; |
||||||
|
using ICSharpCode.AvalonEdit.Rendering; |
||||||
|
using ICSharpCode.Core; |
||||||
|
|
||||||
|
namespace EmbeddedImageAddIn |
||||||
|
{ |
||||||
|
/// <summary>
|
||||||
|
/// Implementation of AvalonEdit element generator.
|
||||||
|
/// This class looks for image tags and produces ImageElements to visually represent those images.
|
||||||
|
/// </summary>
|
||||||
|
public class ImageElementGenerator : VisualLineElementGenerator |
||||||
|
{ |
||||||
|
readonly static Regex imageRegex = new Regex(@"<<IMAGE:([\w\d\\./,\- :]+)>>"); |
||||||
|
|
||||||
|
readonly string baseDirectory; |
||||||
|
|
||||||
|
public ImageElementGenerator(string baseDirectory) |
||||||
|
{ |
||||||
|
this.baseDirectory = baseDirectory; |
||||||
|
} |
||||||
|
|
||||||
|
Match GetMatch(int startOffset) |
||||||
|
{ |
||||||
|
DocumentLine endLine = CurrentContext.VisualLine.LastDocumentLine; |
||||||
|
string relevantText = CurrentContext.Document.GetText(startOffset, endLine.EndOffset - startOffset); |
||||||
|
return imageRegex.Match(relevantText); |
||||||
|
} |
||||||
|
|
||||||
|
/// Gets the first offset >= startOffset where the generator wants to construct
|
||||||
|
/// an element.
|
||||||
|
/// Return -1 to signal no interest.
|
||||||
|
public override int GetFirstInterestedOffset(int startOffset) |
||||||
|
{ |
||||||
|
Match m = GetMatch(startOffset); |
||||||
|
return m.Success ? startOffset + m.Index : -1; |
||||||
|
} |
||||||
|
|
||||||
|
/// Constructs an element at the specified offset.
|
||||||
|
/// May return null if no element should be constructed.
|
||||||
|
public override VisualLineElement ConstructElement(int offset) |
||||||
|
{ |
||||||
|
Match m = GetMatch(offset); |
||||||
|
// check whether there's a match exactly at offset
|
||||||
|
if (m.Success && m.Index == 0) { |
||||||
|
string fileName = Path.Combine(baseDirectory, m.Groups[1].Value); |
||||||
|
ImageSource image = ImageCache.GetImage(FileName.Create(fileName)); |
||||||
|
if (image != null) { |
||||||
|
// Pass the length of the match to the 'documentLength' parameter of ImageElement.
|
||||||
|
return new ImageElement(fileName, image, m.Length); |
||||||
|
} |
||||||
|
} |
||||||
|
return null; |
||||||
|
} |
||||||
|
} |
||||||
|
} |
@ -0,0 +1,39 @@ |
|||||||
|
// Copyright (c) AlphaSierraPapa for the SharpDevelop Team (for details please see \doc\copyright.txt)
|
||||||
|
// This code is distributed under MIT X11 license (for details please see \doc\license.txt)
|
||||||
|
|
||||||
|
using System; |
||||||
|
using System.IO; |
||||||
|
using ICSharpCode.Core; |
||||||
|
using ICSharpCode.SharpDevelop.Editor; |
||||||
|
using ICSharpCode.SharpDevelop.Gui; |
||||||
|
using Microsoft.Win32; |
||||||
|
|
||||||
|
namespace EmbeddedImageAddIn |
||||||
|
{ |
||||||
|
/// <summary>
|
||||||
|
/// "Edit > Insert > Image" menu command.
|
||||||
|
/// </summary>
|
||||||
|
public class InsertImageCommand : AbstractMenuCommand |
||||||
|
{ |
||||||
|
public override void Run() |
||||||
|
{ |
||||||
|
if (WorkbenchSingleton.Workbench.ActiveViewContent == null) |
||||||
|
return; |
||||||
|
ITextEditorProvider provider = WorkbenchSingleton.Workbench.ActiveViewContent.GetService(typeof(ITextEditorProvider)) as ITextEditorProvider; |
||||||
|
if (provider == null) |
||||||
|
return; |
||||||
|
OpenFileDialog dlg = new OpenFileDialog(); |
||||||
|
dlg.Filter = "Image files|*.png;*.jpg;*.gif;*.bmp;*.jpeg|All files|*.*"; |
||||||
|
dlg.CheckFileExists = true; |
||||||
|
dlg.DereferenceLinks = true; |
||||||
|
string baseDirectory = Path.GetDirectoryName(provider.TextEditor.FileName); |
||||||
|
dlg.InitialDirectory = baseDirectory; |
||||||
|
if (dlg.ShowDialog() == true) { |
||||||
|
string relativePath = FileUtility.GetRelativePath(baseDirectory, dlg.FileName); |
||||||
|
if (!Path.IsPathRooted(relativePath)) |
||||||
|
relativePath = relativePath.Replace('\\', '/'); |
||||||
|
provider.TextEditor.Document.Insert(provider.TextEditor.Caret.Offset, "<<IMAGE:" + relativePath + ">>"); |
||||||
|
} |
||||||
|
} |
||||||
|
} |
||||||
|
} |
Loading…
Reference in new issue