Browse Source

Add "embedded image" sample AddIn.

pull/14/head
Daniel Grunwald 15 years ago
parent
commit
000d891754
  1. 31
      samples/EmbeddedImageAddIn/Configuration/AssemblyInfo.cs
  2. 20
      samples/EmbeddedImageAddIn/EmbeddedImageAddIn.addin
  3. 80
      samples/EmbeddedImageAddIn/EmbeddedImageAddIn.csproj
  4. 18
      samples/EmbeddedImageAddIn/EmbeddedImageAddIn.sln
  5. 38
      samples/EmbeddedImageAddIn/EmbeddedImageLanguageBinding.cs
  6. 58
      samples/EmbeddedImageAddIn/ImageCache.cs
  7. 101
      samples/EmbeddedImageAddIn/ImageElement.cs
  8. 62
      samples/EmbeddedImageAddIn/ImageElementGenerator.cs
  9. 39
      samples/EmbeddedImageAddIn/InsertImageCommand.cs

31
samples/EmbeddedImageAddIn/Configuration/AssemblyInfo.cs

@ -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.*")]

20
samples/EmbeddedImageAddIn/EmbeddedImageAddIn.addin

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

80
samples/EmbeddedImageAddIn/EmbeddedImageAddIn.csproj

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

18
samples/EmbeddedImageAddIn/EmbeddedImageAddIn.sln

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

38
samples/EmbeddedImageAddIn/EmbeddedImageLanguageBinding.cs

@ -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();
}
}
}

58
samples/EmbeddedImageAddIn/ImageCache.cs

@ -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;
}
}
}

101
samples/EmbeddedImageAddIn/ImageElement.cs

@ -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));
}
}
}
}

62
samples/EmbeddedImageAddIn/ImageElementGenerator.cs

@ -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;
}
}
}

39
samples/EmbeddedImageAddIn/InsertImageCommand.cs

@ -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…
Cancel
Save