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

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

@ -22,6 +22,8 @@ namespace CSharpBinding.FormsDesigner @@ -22,6 +22,8 @@ namespace CSharpBinding.FormsDesigner
{
public class CSharpDesignerLoader : AbstractCodeDomDesignerLoader
{
IUnresolvedTypeDefinition primaryPart;
readonly CodeDomProvider codeDomProvider = new CSharpCodeProvider();
readonly ICSharpDesignerLoaderContext context;
@ -43,6 +45,18 @@ namespace CSharpBinding.FormsDesigner @@ -43,6 +45,18 @@ namespace CSharpBinding.FormsDesigner
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:
// - Parse main file
// - Find other files containing parts of the form
@ -59,7 +73,6 @@ namespace CSharpBinding.FormsDesigner @@ -59,7 +73,6 @@ namespace CSharpBinding.FormsDesigner
var compilation = context.GetCompilation();
// Find designer class
IUnresolvedTypeDefinition primaryPart;
ITypeDefinition designerClass = FormsDesignerSecondaryDisplayBinding.GetDesignableClass(primaryParseInfo.UnresolvedFile, compilation, out primaryPart);
IMethod initializeComponents = FormsDesignerSecondaryDisplayBinding.GetInitializeComponents(designerClass);
@ -115,7 +128,7 @@ namespace CSharpBinding.FormsDesigner @@ -115,7 +128,7 @@ namespace CSharpBinding.FormsDesigner
LoggingService.Debug("NRefactoryDesignerLoader.Parse() finished");
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.");
}

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

@ -0,0 +1,153 @@ @@ -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; @@ -7,6 +7,7 @@ using ICSharpCode.FormsDesigner;
using ICSharpCode.NRefactory.Editor;
using ICSharpCode.NRefactory.TypeSystem;
using ICSharpCode.SharpDevelop;
using ICSharpCode.SharpDevelop.Editor;
using CSharpBinding.Parser;
namespace CSharpBinding.FormsDesigner
@ -51,6 +52,11 @@ namespace CSharpBinding.FormsDesigner @@ -51,6 +52,11 @@ namespace CSharpBinding.FormsDesigner
}
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 @@ -16,5 +16,6 @@ namespace CSharpBinding.FormsDesigner
CSharpFullParseInformation GetPrimaryFileParseInformation();
ICompilation GetCompilation();
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 @@ -64,18 +64,20 @@ namespace CSharpBinding.Refactoring
var view = SD.FileService.OpenFile(new FileName(match.Region.FileName), jumpTo);
var editor = view.GetRequiredService<ITextEditor>();
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 resolver = context.GetResolverStateAfter(node);
var builder = new TypeSystemAstBuilder(resolver);
var delegateDecl = builder.ConvertEntity(eventDefinition.ReturnType.GetDefinition()) as DelegateDeclaration;
if (delegateDecl == null) return;
var throwStmt = new ThrowStatement(new ObjectCreateExpression(context.CreateShortType("System", "NotImplementedException")));
var decl = new MethodDeclaration() {
ReturnType = delegateDecl.ReturnType.Clone(),
Name = name,
Body = new BlockStatement() {
new ThrowStatement(new ObjectCreateExpression(context.CreateShortType("System", "NotImplementedException")))
throwStmt
}
};
var param = delegateDecl.Parameters.Select(p => p.Clone()).OfType<ParameterDeclaration>().ToArray();
@ -88,7 +90,9 @@ namespace CSharpBinding.Refactoring @@ -88,7 +90,9 @@ namespace CSharpBinding.Refactoring
// TODO InsertWithCursor not implemented!
//script.InsertWithCursor("Insert event handler", Script.InsertPosition.End, decl).RunSynchronously();
} else {
// TODO does not jump correctly...
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 @@ -33,7 +33,17 @@ namespace CSharpBinding.Refactoring
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))
@ -63,8 +73,8 @@ namespace CSharpBinding.Refactoring @@ -63,8 +73,8 @@ namespace CSharpBinding.Refactoring
InitializeServices();
}
public SDRefactoringContext(ITextEditor editor, CSharpAstResolver resolver, TextLocation location)
: base(resolver, CancellationToken.None)
public SDRefactoringContext(ITextEditor editor, CSharpAstResolver resolver, TextLocation location, CancellationToken cancellationToken = default(CancellationToken))
: base(resolver, cancellationToken)
{
this.resolver = resolver;
this.editor = editor;

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

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

Loading…
Cancel
Save