Browse Source

add basic support for adding event handlers in FormsDesigner

pull/45/merge
Siegfried Pammer 12 years ago
parent
commit
e9b60dbf09
  1. 1
      src/AddIns/BackendBindings/CSharpBinding/Project/CSharpBinding.csproj
  2. 17
      src/AddIns/BackendBindings/CSharpBinding/Project/Src/FormsDesigner/CSharpDesignerLoader.cs
  3. 153
      src/AddIns/BackendBindings/CSharpBinding/Project/Src/FormsDesigner/CSharpEventBindingService.cs
  4. 6
      src/AddIns/BackendBindings/CSharpBinding/Project/Src/FormsDesigner/CSharpFormsDesignerLoaderContext.cs
  5. 1
      src/AddIns/BackendBindings/CSharpBinding/Project/Src/FormsDesigner/ICSharpDesignerLoaderContext.cs
  6. 8
      src/AddIns/BackendBindings/CSharpBinding/Project/Src/Refactoring/CSharpCodeGenerator.cs
  7. 16
      src/AddIns/BackendBindings/CSharpBinding/Project/Src/Refactoring/SDRefactoringContext.cs
  8. 7
      src/AddIns/DisplayBindings/FormsDesigner/Project/Src/DesignerViewContent.cs

1
src/AddIns/BackendBindings/CSharpBinding/Project/CSharpBinding.csproj

@ -81,6 +81,7 @@
<Compile Include="Src\FormsDesigner\CSharpDesignerGenerator.cs" /> <Compile Include="Src\FormsDesigner\CSharpDesignerGenerator.cs" />
<Compile Include="Src\FormsDesigner\CSharpDesignerLoader.cs" /> <Compile Include="Src\FormsDesigner\CSharpDesignerLoader.cs" />
<Compile Include="Src\FormsDesigner\CSharpDesignerLoaderProvider.cs" /> <Compile Include="Src\FormsDesigner\CSharpDesignerLoaderProvider.cs" />
<Compile Include="Src\FormsDesigner\CSharpEventBindingService.cs" />
<Compile Include="Src\FormsDesigner\CSharpFormsDesignerLoaderContext.cs" /> <Compile Include="Src\FormsDesigner\CSharpFormsDesignerLoaderContext.cs" />
<Compile Include="Src\FormsDesigner\ICSharpDesignerLoaderContext.cs" /> <Compile Include="Src\FormsDesigner\ICSharpDesignerLoaderContext.cs" />
<Compile Include="Src\FormsDesigner\SecondaryDisplayBinding.cs" /> <Compile Include="Src\FormsDesigner\SecondaryDisplayBinding.cs" />

17
src/AddIns/BackendBindings/CSharpBinding/Project/Src/FormsDesigner/CSharpDesignerLoader.cs

@ -22,6 +22,8 @@ namespace CSharpBinding.FormsDesigner
{ {
public class CSharpDesignerLoader : AbstractCodeDomDesignerLoader public class CSharpDesignerLoader : AbstractCodeDomDesignerLoader
{ {
IUnresolvedTypeDefinition primaryPart;
readonly CodeDomProvider codeDomProvider = new CSharpCodeProvider(); readonly CodeDomProvider codeDomProvider = new CSharpCodeProvider();
readonly ICSharpDesignerLoaderContext context; readonly ICSharpDesignerLoaderContext context;
@ -43,6 +45,18 @@ namespace CSharpBinding.FormsDesigner
return base.IsReloadNeeded() || context.DesignerCodeFileDocument.Version.Equals(lastTextContentVersion); return base.IsReloadNeeded() || context.DesignerCodeFileDocument.Version.Equals(lastTextContentVersion);
} }
protected override void Initialize()
{
base.Initialize();
base.DesignerLoaderHost.AddService(typeof(System.ComponentModel.Design.IEventBindingService), new CSharpEventBindingService(context, base.DesignerLoaderHost, this));
}
public ITypeDefinition GetPrimaryTypeDefinition()
{
return primaryPart.Resolve(new SimpleTypeResolveContext(context.GetCompilation().MainAssembly)).GetDefinition();
}
// Steps to load the designer: // Steps to load the designer:
// - Parse main file // - Parse main file
// - Find other files containing parts of the form // - Find other files containing parts of the form
@ -59,7 +73,6 @@ namespace CSharpBinding.FormsDesigner
var compilation = context.GetCompilation(); var compilation = context.GetCompilation();
// Find designer class // Find designer class
IUnresolvedTypeDefinition primaryPart;
ITypeDefinition designerClass = FormsDesignerSecondaryDisplayBinding.GetDesignableClass(primaryParseInfo.UnresolvedFile, compilation, out primaryPart); ITypeDefinition designerClass = FormsDesignerSecondaryDisplayBinding.GetDesignableClass(primaryParseInfo.UnresolvedFile, compilation, out primaryPart);
IMethod initializeComponents = FormsDesignerSecondaryDisplayBinding.GetInitializeComponents(designerClass); IMethod initializeComponents = FormsDesignerSecondaryDisplayBinding.GetInitializeComponents(designerClass);
@ -115,7 +128,7 @@ namespace CSharpBinding.FormsDesigner
LoggingService.Debug("NRefactoryDesignerLoader.Parse() finished"); LoggingService.Debug("NRefactoryDesignerLoader.Parse() finished");
if (!isFirstClassInFile) { if (!isFirstClassInFile) {
MessageService.ShowWarning("The form must be the first class in the file in order for form resources be compiled correctly.\n" + MessageService.ShowWarning("The form must be the first class in the file in order for form resources to be compiled correctly.\n" +
"Please move other classes below the form class definition or move them to other files."); "Please move other classes below the form class definition or move them to other files.");
} }

153
src/AddIns/BackendBindings/CSharpBinding/Project/Src/FormsDesigner/CSharpEventBindingService.cs

@ -0,0 +1,153 @@
// Copyright (c) AlphaSierraPapa for the SharpDevelop Team (for details please see \doc\copyright.txt)
// This code is distributed under the GNU LGPL (for details please see \doc\license.txt)
using System;
using System.Collections;
using System.ComponentModel;
using System.Linq;
using System.Reflection;
using System.Windows.Threading;
using ICSharpCode.Core;
using ICSharpCode.FormsDesigner.Gui.OptionPanels;
using ICSharpCode.NRefactory.CSharp;
using ICSharpCode.NRefactory.TypeSystem;
using ICSharpCode.SharpDevelop;
using ICSharpCode.SharpDevelop.Gui;
using CSharpBinding.Refactoring;
namespace CSharpBinding.FormsDesigner
{
public class CSharpEventBindingService : System.ComponentModel.Design.EventBindingService
{
readonly CSharpDesignerLoader loader;
readonly ICSharpDesignerLoaderContext context;
public CSharpEventBindingService(ICSharpDesignerLoaderContext context, IServiceProvider provider, CSharpDesignerLoader loader) : base(provider)
{
this.loader = loader;
if (context == null)
throw new ArgumentNullException("context");
if (loader == null)
throw new ArgumentNullException("loader");
this.context = context;
this.loader = loader;
}
protected override string CreateUniqueMethodName(IComponent component, EventDescriptor e)
{
string componentName = GetComponentName(component);
return GetEventHandlerName(componentName, e.DisplayName);
}
string GetComponentName(IComponent component)
{
string siteName = component.Site.Name;
return Char.ToUpper(siteName[0]) + siteName.Substring(1);
}
string GetEventHandlerName(string componentName, string eventName)
{
string eventHandlerNameFormat = GetEventHandlerNameFormat();
return String.Format(eventHandlerNameFormat, componentName, eventName);
}
string GetEventHandlerNameFormat()
{
if (GeneralOptionsPanel.GenerateVisualStudioStyleEventHandlers) {
return "{0}_{1}";
}
return "{0}{1}";
}
protected override ICollection GetCompatibleMethods(EventDescriptor e)
{
ITypeDefinition definition = loader.GetPrimaryTypeDefinition();
ArrayList compatibleMethods = new ArrayList();
MethodInfo methodInfo = e.EventType.GetMethod("Invoke");
var methodInfoParameters = methodInfo.GetParameters();
foreach (IMethod method in definition.Methods) {
if (method.Parameters.Count == methodInfoParameters.Length) {
bool found = true;
for (int i = 0; i < methodInfoParameters.Length; ++i) {
ParameterInfo pInfo = methodInfoParameters[i];
IParameter p = method.Parameters[i];
if (p.Type.ReflectionName != pInfo.ParameterType.ToString()) {
found = false;
break;
}
}
if (found) {
compatibleMethods.Add(method.Name);
}
}
}
return compatibleMethods;
}
protected override bool ShowCode()
{
if (context != null) {
context.ShowSourceCode();
return true;
}
return false;
}
protected override bool ShowCode(int lineNumber)
{
if (context != null) {
context.ShowSourceCode(lineNumber);
return true;
}
return false;
}
protected override bool ShowCode(IComponent component, EventDescriptor edesc, string methodName)
{
// There were reports of an ArgumentNullException caused by edesc==null.
// Looking at the .NET code calling this method, this can happen when there are two calls to ShowCode() before the Application.Idle
// event gets raised. In that case, ShowCode() already was called for the second set of arguments, and we can safely ignore
// the call with edesc==null.
if (context != null && edesc != null) {
// TODO : does not properly update events list in properties pad!
IEvent evt = FindEvent(edesc);
if (evt == null) return false;
context.ShowSourceCode();
Dispatcher.CurrentDispatcher.BeginInvoke(DispatcherPriority.Normal, (Action)delegate { InsertEventHandlerInternal(methodName, evt); });
return true;
}
return false;
}
void InsertEventHandlerInternal(string methodName, IEvent evt)
{
CSharpCodeGenerator generator = new CSharpCodeGenerator();
var primary = loader.GetPrimaryTypeDefinition();
var evtHandler = primary.GetMethods(m => m.Name == methodName, GetMemberOptions.IgnoreInheritedMembers).FirstOrDefault();
if (evtHandler == null) {
generator.InsertEventHandler(primary, methodName, evt, true);
}
else {
CSharpBinding.Parser.CSharpFullParseInformation parseInfo;
var node = evtHandler.GetDeclaration(out parseInfo) as MethodDeclaration;
if (node != null && !node.Body.IsNull) {
var location = node.Body.FirstChild.StartLocation;
var firstStatement = node.Body.Children.OfType<Statement>().FirstOrDefault();
if (firstStatement != null)
location = firstStatement.StartLocation;
// TODO : does not jump correctly...
SD.FileService.JumpToFilePosition(new FileName(evtHandler.Region.FileName), location.Line, location.Column);
}
}
}
IEvent FindEvent(EventDescriptor edesc)
{
var compilation = context.GetCompilation();
var type = compilation.FindType(edesc.ComponentType);
return type.GetEvents(evt => evt.Name == edesc.Name).FirstOrDefault();
}
}
}

6
src/AddIns/BackendBindings/CSharpBinding/Project/Src/FormsDesigner/CSharpFormsDesignerLoaderContext.cs

@ -7,6 +7,7 @@ using ICSharpCode.FormsDesigner;
using ICSharpCode.NRefactory.Editor; using ICSharpCode.NRefactory.Editor;
using ICSharpCode.NRefactory.TypeSystem; using ICSharpCode.NRefactory.TypeSystem;
using ICSharpCode.SharpDevelop; using ICSharpCode.SharpDevelop;
using ICSharpCode.SharpDevelop.Editor;
using CSharpBinding.Parser; using CSharpBinding.Parser;
namespace CSharpBinding.FormsDesigner namespace CSharpBinding.FormsDesigner
@ -51,6 +52,11 @@ namespace CSharpBinding.FormsDesigner
} }
throw new InvalidOperationException("Designer file not found"); throw new InvalidOperationException("Designer file not found");
} }
public void ShowSourceCode(int lineNumber = 0)
{
viewContent.ShowSourceCode(lineNumber);
}
} }
} }

1
src/AddIns/BackendBindings/CSharpBinding/Project/Src/FormsDesigner/ICSharpDesignerLoaderContext.cs

@ -16,5 +16,6 @@ namespace CSharpBinding.FormsDesigner
CSharpFullParseInformation GetPrimaryFileParseInformation(); CSharpFullParseInformation GetPrimaryFileParseInformation();
ICompilation GetCompilation(); ICompilation GetCompilation();
IDocument GetDocument(FileName fileName); IDocument GetDocument(FileName fileName);
void ShowSourceCode(int lineNumber = 0);
} }
} }

8
src/AddIns/BackendBindings/CSharpBinding/Project/Src/Refactoring/CSharpCodeGenerator.cs

@ -64,18 +64,20 @@ namespace CSharpBinding.Refactoring
var view = SD.FileService.OpenFile(new FileName(match.Region.FileName), jumpTo); var view = SD.FileService.OpenFile(new FileName(match.Region.FileName), jumpTo);
var editor = view.GetRequiredService<ITextEditor>(); var editor = view.GetRequiredService<ITextEditor>();
var last = match.Members.LastOrDefault() ?? (IUnresolvedEntity)match; var last = match.Members.LastOrDefault() ?? (IUnresolvedEntity)match;
var context = SDRefactoringContext.Create(editor.FileName, editor.Document, last.BodyRegion.End, CancellationToken.None); editor.Caret.Location = last.BodyRegion.End;
var context = SDRefactoringContext.Create(editor, CancellationToken.None);
var node = context.RootNode.GetNodeAt<EntityDeclaration>(last.Region.Begin); var node = context.RootNode.GetNodeAt<EntityDeclaration>(last.Region.Begin);
var resolver = context.GetResolverStateAfter(node); var resolver = context.GetResolverStateAfter(node);
var builder = new TypeSystemAstBuilder(resolver); var builder = new TypeSystemAstBuilder(resolver);
var delegateDecl = builder.ConvertEntity(eventDefinition.ReturnType.GetDefinition()) as DelegateDeclaration; var delegateDecl = builder.ConvertEntity(eventDefinition.ReturnType.GetDefinition()) as DelegateDeclaration;
if (delegateDecl == null) return; if (delegateDecl == null) return;
var throwStmt = new ThrowStatement(new ObjectCreateExpression(context.CreateShortType("System", "NotImplementedException")));
var decl = new MethodDeclaration() { var decl = new MethodDeclaration() {
ReturnType = delegateDecl.ReturnType.Clone(), ReturnType = delegateDecl.ReturnType.Clone(),
Name = name, Name = name,
Body = new BlockStatement() { Body = new BlockStatement() {
new ThrowStatement(new ObjectCreateExpression(context.CreateShortType("System", "NotImplementedException"))) throwStmt
} }
}; };
var param = delegateDecl.Parameters.Select(p => p.Clone()).OfType<ParameterDeclaration>().ToArray(); var param = delegateDecl.Parameters.Select(p => p.Clone()).OfType<ParameterDeclaration>().ToArray();
@ -88,7 +90,9 @@ namespace CSharpBinding.Refactoring
// TODO InsertWithCursor not implemented! // TODO InsertWithCursor not implemented!
//script.InsertWithCursor("Insert event handler", Script.InsertPosition.End, decl).RunSynchronously(); //script.InsertWithCursor("Insert event handler", Script.InsertPosition.End, decl).RunSynchronously();
} else { } else {
// TODO does not jump correctly...
script.InsertAfter(node, decl); script.InsertAfter(node, decl);
editor.JumpTo(throwStmt.StartLocation.Line, throwStmt.StartLocation.Column);
} }
} }
} }

16
src/AddIns/BackendBindings/CSharpBinding/Project/Src/Refactoring/SDRefactoringContext.cs

@ -33,7 +33,17 @@ namespace CSharpBinding.Refactoring
public static SDRefactoringContext Create(ITextEditor editor, CancellationToken cancellationToken) public static SDRefactoringContext Create(ITextEditor editor, CancellationToken cancellationToken)
{ {
return Create(editor.FileName, editor.Document, editor.Caret.Location, cancellationToken); var parseInfo = SD.ParserService.Parse(editor.FileName, editor.Document, cancellationToken: cancellationToken) as CSharpFullParseInformation;
var compilation = SD.ParserService.GetCompilationForFile(editor.FileName);
CSharpAstResolver resolver;
if (parseInfo != null) {
resolver = parseInfo.GetResolver(compilation);
} else {
// create dummy refactoring context
resolver = new CSharpAstResolver(compilation, new SyntaxTree());
}
var context = new SDRefactoringContext(editor, resolver, editor.Caret.Location, cancellationToken);
return context;
} }
public static SDRefactoringContext Create(FileName fileName, ITextSource textSource, TextLocation location = default(TextLocation), CancellationToken cancellationToken = default(CancellationToken)) public static SDRefactoringContext Create(FileName fileName, ITextSource textSource, TextLocation location = default(TextLocation), CancellationToken cancellationToken = default(CancellationToken))
@ -63,8 +73,8 @@ namespace CSharpBinding.Refactoring
InitializeServices(); InitializeServices();
} }
public SDRefactoringContext(ITextEditor editor, CSharpAstResolver resolver, TextLocation location) public SDRefactoringContext(ITextEditor editor, CSharpAstResolver resolver, TextLocation location, CancellationToken cancellationToken = default(CancellationToken))
: base(resolver, CancellationToken.None) : base(resolver, cancellationToken)
{ {
this.resolver = resolver; this.resolver = resolver;
this.editor = editor; this.editor = editor;

7
src/AddIns/DisplayBindings/FormsDesigner/Project/Src/DesignerViewContent.cs

@ -633,14 +633,9 @@ namespace ICSharpCode.FormsDesigner
this.DesignerCodeFile.IsDirty = isDirty; this.DesignerCodeFile.IsDirty = isDirty;
} }
public void ShowSourceCode() public void ShowSourceCode(int lineNumber = 0)
{ {
this.WorkbenchWindow.ActiveViewContent = this.PrimaryViewContent; this.WorkbenchWindow.ActiveViewContent = this.PrimaryViewContent;
}
public void ShowSourceCode(int lineNumber)
{
ShowSourceCode();
ITextEditor editor = this.primaryViewContent.GetService<ITextEditor>(); ITextEditor editor = this.primaryViewContent.GetService<ITextEditor>();
if (editor != null) { if (editor != null) {
editor.JumpTo(lineNumber, 1); editor.JumpTo(lineNumber, 1);

Loading…
Cancel
Save