9 changed files with 447 additions and 0 deletions
@ -0,0 +1,31 @@
@@ -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 @@
@@ -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 @@
@@ -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 @@
@@ -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 @@
@@ -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 @@
@@ -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 @@
@@ -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 @@
@@ -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 @@
@@ -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