Browse Source
- refactored ParameterListComparer - added SignatureComparer - added IEditorUIService and IInlineUIElement - updated some snippets - added basic implementation of OverrideToStringMethod refactoring - added ClassCodeGeneratorMenuBuilder git-svn-id: svn://svn.sharpdevelop.net/sharpdevelop/trunk@5241 1ccf3a8d-04fe-1044-b7c0-cef0b8235c61pull/1/head
23 changed files with 621 additions and 52 deletions
@ -0,0 +1,67 @@
@@ -0,0 +1,67 @@
|
||||
// <file>
|
||||
// <copyright see="prj:///doc/copyright.txt"/>
|
||||
// <license see="prj:///doc/license.txt"/>
|
||||
// <owner name="Siegfried Pammer" email="siegfriedpammer@gmail.com" />
|
||||
// <version>$Revision$</version>
|
||||
// </file>
|
||||
|
||||
using System; |
||||
using System.Windows; |
||||
using ICSharpCode.AvalonEdit.Document; |
||||
using ICSharpCode.AvalonEdit.Rendering; |
||||
using ICSharpCode.SharpDevelop.Editor; |
||||
|
||||
namespace ICSharpCode.AvalonEdit.AddIn |
||||
{ |
||||
public class InlineUIElementGenerator : VisualLineElementGenerator, IInlineUIElement |
||||
{ |
||||
ITextAnchor anchor; |
||||
UIElement element; |
||||
TextView textView; |
||||
|
||||
public InlineUIElementGenerator(TextView textView, UIElement element, ITextAnchor anchor) |
||||
{ |
||||
this.textView = textView; |
||||
this.element = element; |
||||
this.anchor = anchor; |
||||
} |
||||
|
||||
public override int GetFirstInterestedOffset(int startOffset) |
||||
{ |
||||
if (anchor.Offset >= startOffset) |
||||
return anchor.Offset; |
||||
|
||||
return -1; |
||||
} |
||||
|
||||
public override VisualLineElement ConstructElement(int offset) |
||||
{ |
||||
if (this.anchor.Offset == offset) |
||||
return new InlineObjectElement(0, element); |
||||
|
||||
return null; |
||||
} |
||||
|
||||
public void Remove() |
||||
{ |
||||
this.textView.ElementGenerators.Remove(this); |
||||
} |
||||
} |
||||
|
||||
public class AvalonEditEditorUIService : IEditorUIService |
||||
{ |
||||
TextView textView; |
||||
|
||||
public AvalonEditEditorUIService(TextView textView) |
||||
{ |
||||
this.textView = textView; |
||||
} |
||||
|
||||
public IInlineUIElement CreateInlineUIElement(ITextAnchor position, UIElement element) |
||||
{ |
||||
InlineUIElementGenerator inline = new InlineUIElementGenerator(textView, element, position); |
||||
this.textView.ElementGenerators.Add(inline); |
||||
return inline; |
||||
} |
||||
} |
||||
} |
@ -0,0 +1,113 @@
@@ -0,0 +1,113 @@
|
||||
// <file>
|
||||
// <copyright see="prj:///doc/copyright.txt"/>
|
||||
// <license see="prj:///doc/license.txt"/>
|
||||
// <owner name="Siegfried Pammer" email="siegfriedpammer@gmail.com" />
|
||||
// <version>$Revision$</version>
|
||||
// </file>
|
||||
|
||||
using System; |
||||
using System.Linq; |
||||
using System.Collections.Generic; |
||||
using System.Windows.Forms; |
||||
|
||||
using ICSharpCode.Core; |
||||
using ICSharpCode.Core.Presentation; |
||||
using ICSharpCode.Core.WinForms; |
||||
using ICSharpCode.NRefactory; |
||||
using ICSharpCode.SharpDevelop; |
||||
using ICSharpCode.SharpDevelop.Bookmarks; |
||||
using ICSharpCode.SharpDevelop.Dom; |
||||
using ICSharpCode.SharpDevelop.Dom.Refactoring; |
||||
using ICSharpCode.SharpDevelop.Editor; |
||||
using ICSharpCode.SharpDevelop.Gui.ClassBrowser; |
||||
using ICSharpCode.SharpDevelop.Refactoring; |
||||
|
||||
namespace SharpRefactoring |
||||
{ |
||||
public class ClassCodeGeneratorMenuBuilder : ISubmenuBuilder, IMenuItemBuilder |
||||
{ |
||||
public System.Collections.ICollection BuildItems(Codon codon, object owner) |
||||
{ |
||||
return BuildSubmenu(codon, owner).TranslateToWpf(); |
||||
} |
||||
|
||||
public System.Windows.Forms.ToolStripItem[] BuildSubmenu(Codon codon, object owner) |
||||
{ |
||||
List<ToolStripItem> resultItems = new List<ToolStripItem>(); |
||||
|
||||
IClass c; |
||||
ClassNode classNode = owner as ClassNode; |
||||
if (classNode != null) { |
||||
c = classNode.Class; |
||||
} else { |
||||
ClassBookmark bookmark = (ClassBookmark)owner; |
||||
c = bookmark.Class; |
||||
} |
||||
|
||||
LanguageProperties language = c.ProjectContent.Language; |
||||
if (language != LanguageProperties.CSharp) |
||||
return resultItems.ToArray(); |
||||
|
||||
AddImplementAbstractClassCommands(c, resultItems); |
||||
|
||||
return resultItems.ToArray(); |
||||
} |
||||
|
||||
void AddImplementAbstractClassCommandItems(List<ToolStripItem> subItems, IClass c) |
||||
{ |
||||
IAmbience ambience = AmbienceService.GetCurrentAmbience(); |
||||
ambience.ConversionFlags = ConversionFlags.ShowTypeParameterList; |
||||
foreach (IReturnType rt in c.BaseTypes) { |
||||
IClass abstractClass = rt.GetUnderlyingClass(); |
||||
if (abstractClass != null && abstractClass.ClassType == ClassType.Class && abstractClass.IsAbstract) { |
||||
IReturnType rtCopy = rt; // copy for access by anonymous method
|
||||
EventHandler eh = delegate { |
||||
var d = FindReferencesAndRenameHelper.GetDocument(c); |
||||
if (d != null) |
||||
ImplementAbstractClass(d, c, abstractClass); |
||||
ParserService.ParseCurrentViewContent(); |
||||
}; |
||||
subItems.Add(new MenuCommand(ambience.Convert(abstractClass), eh)); |
||||
} |
||||
} |
||||
} |
||||
|
||||
void AddImplementAbstractClassCommands(IClass c, List<ToolStripItem> list) |
||||
{ |
||||
List<ToolStripItem> subItems = new List<ToolStripItem>(); |
||||
AddImplementAbstractClassCommandItems(subItems, c); |
||||
|
||||
if (subItems.Count > 0) { |
||||
list.Add(new ICSharpCode.Core.WinForms.Menu("${res:SharpDevelop.Refactoring.ImplementAbstractClass}", subItems.ToArray())); |
||||
} |
||||
} |
||||
|
||||
#region Code generation
|
||||
void ImplementAbstractClass(IDocument document, IClass target, IClass abstractClass) |
||||
{ |
||||
CodeGenerator generator = target.ProjectContent.Language.CodeGenerator; |
||||
RefactoringDocumentAdapter doc = new RefactoringDocumentAdapter(document); |
||||
var pos = doc.OffsetToPosition(doc.PositionToOffset(target.BodyRegion.EndLine, target.BodyRegion.EndColumn) - 1); |
||||
ClassFinder context = new ClassFinder(target, pos.Line, pos.Column); |
||||
|
||||
foreach (IMember member in abstractClass.AllMembers.Where(m => m.IsAbstract && !HasMember(m, target))) { |
||||
generator.InsertCodeAtEnd(target.BodyRegion, doc, generator.GetOverridingMethod(member, context)); |
||||
} |
||||
} |
||||
#endregion
|
||||
|
||||
#region Helpers
|
||||
SignatureComparer comparer = new SignatureComparer(); |
||||
|
||||
bool HasMember(IMember member, IClass containingClass) |
||||
{ |
||||
foreach (IMember m in containingClass.AllMembers) { |
||||
if (comparer.Equals(member, m)) |
||||
return true; |
||||
} |
||||
|
||||
return false; |
||||
} |
||||
#endregion
|
||||
} |
||||
} |
@ -0,0 +1,165 @@
@@ -0,0 +1,165 @@
|
||||
// <file>
|
||||
// <copyright see="prj:///doc/copyright.txt"/>
|
||||
// <license see="prj:///doc/license.txt"/>
|
||||
// <owner name="Siegfried Pammer" email="siegfriedpammer@gmail.com" />
|
||||
// <version>$Revision$</version>
|
||||
// </file>
|
||||
|
||||
using System; |
||||
using System.Collections.Generic; |
||||
using System.Linq; |
||||
using System.Windows; |
||||
using System.Windows.Controls; |
||||
using System.Windows.Media; |
||||
|
||||
using ICSharpCode.Core; |
||||
using ICSharpCode.NRefactory.Ast; |
||||
using ICSharpCode.SharpDevelop; |
||||
using ICSharpCode.SharpDevelop.Dom; |
||||
using ICSharpCode.SharpDevelop.Dom.Refactoring; |
||||
using ICSharpCode.SharpDevelop.Editor; |
||||
|
||||
namespace SharpRefactoring.Gui |
||||
{ |
||||
public abstract class InlineRefactorDialog : DockPanel |
||||
{ |
||||
protected ITextAnchor anchor; |
||||
protected ITextEditor editor; |
||||
|
||||
public IInlineUIElement Element { get; set; } |
||||
|
||||
public InlineRefactorDialog(ITextEditor editor, ITextAnchor anchor) |
||||
{ |
||||
this.anchor = anchor; |
||||
this.editor = editor; |
||||
|
||||
this.Background = SystemColors.ControlBrush; |
||||
|
||||
Initialize(); |
||||
} |
||||
|
||||
void Initialize() |
||||
{ |
||||
UIElement content = CreateContentElement(); |
||||
|
||||
Button okButton = new Button() { |
||||
Content = StringParser.Parse("${res:Global.OKButtonText}"), |
||||
Margin = new Thickness(3) |
||||
}; |
||||
|
||||
okButton.Click += OKButtonClick; |
||||
|
||||
Button cancelButton = new Button() { |
||||
Content = StringParser.Parse("${res:Global.CancelButtonText}"), |
||||
Margin = new Thickness(3) |
||||
}; |
||||
|
||||
cancelButton.Click += CancelButtonClick; |
||||
|
||||
StackPanel buttonsPanel = new StackPanel() { |
||||
Orientation = Orientation.Horizontal, |
||||
HorizontalAlignment = HorizontalAlignment.Center, |
||||
VerticalAlignment = VerticalAlignment.Center, |
||||
Children = { |
||||
okButton, |
||||
cancelButton |
||||
} |
||||
}; |
||||
|
||||
buttonsPanel.SetValue(DockPanel.DockProperty, Dock.Bottom); |
||||
|
||||
this.Children.Add(buttonsPanel); |
||||
this.Children.Add(content); |
||||
} |
||||
|
||||
protected abstract UIElement CreateContentElement(); |
||||
protected abstract void GenerateCode(CodeGenerator generator, IClass currentClass); |
||||
|
||||
void OKButtonClick(object sender, RoutedEventArgs e) |
||||
{ |
||||
if (Element == null) |
||||
throw new InvalidOperationException("no IInlineUIElement set!"); |
||||
|
||||
ParseInformation parseInfo = ParserService.GetParseInformation(editor.FileName); |
||||
|
||||
if (parseInfo != null) { |
||||
CodeGenerator generator = parseInfo.CompilationUnit.Language.CodeGenerator; |
||||
IClass current = parseInfo.CompilationUnit.GetInnermostClass(editor.Caret.Line, editor.Caret.Column); |
||||
|
||||
GenerateCode(generator, current); |
||||
} |
||||
|
||||
Element.Remove(); |
||||
} |
||||
|
||||
void CancelButtonClick(object sender, RoutedEventArgs e) |
||||
{ |
||||
if (Element == null) |
||||
throw new InvalidOperationException("no IInlineUIElement set!"); |
||||
|
||||
Element.Remove(); |
||||
} |
||||
} |
||||
|
||||
public class OverrideToStringMethodDialog : InlineRefactorDialog |
||||
{ |
||||
ListBox listBox; |
||||
List<EntityWrapper> fields; |
||||
ITextAnchor parameterListAnchor; |
||||
|
||||
public OverrideToStringMethodDialog(ITextEditor editor, ITextAnchor anchor, ITextAnchor parameterListAnchor, IList<IField> fields) |
||||
: base(editor, anchor) |
||||
{ |
||||
this.parameterListAnchor = parameterListAnchor; |
||||
this.fields = fields.Select(f => new EntityWrapper() { Entity = f }).ToList(); |
||||
this.listBox.ItemsSource = this.fields.Select(i => i.Create()); |
||||
} |
||||
|
||||
protected override UIElement CreateContentElement() |
||||
{ |
||||
listBox = new ListBox() { |
||||
Margin = new Thickness(3) |
||||
}; |
||||
|
||||
return listBox; |
||||
} |
||||
|
||||
protected override void GenerateCode(CodeGenerator generator, IClass currentClass) |
||||
{ |
||||
var fields = this.fields |
||||
.Where(f => f.IsChecked) |
||||
.Select(f2 => CreateAssignment(f2.Entity.Name, f2.Entity.Name)) |
||||
.ToArray(); |
||||
generator.InsertCodeInClass(currentClass, new RefactoringDocumentAdapter(editor.Document), anchor.Line, fields); |
||||
} |
||||
|
||||
Statement CreateAssignment(string memberName, string parameter) |
||||
{ |
||||
return new ExpressionStatement( |
||||
new AssignmentExpression( |
||||
new MemberReferenceExpression(new ThisReferenceExpression(), memberName), |
||||
AssignmentOperatorType.Assign, |
||||
new IdentifierExpression(parameter) |
||||
) |
||||
); |
||||
} |
||||
} |
||||
|
||||
class EntityWrapper |
||||
{ |
||||
public IEntity Entity { get; set; } |
||||
public bool IsChecked { get; set; } |
||||
|
||||
public object Create() |
||||
{ |
||||
CheckBox box = new CheckBox() { |
||||
Content = Entity.Name |
||||
}; |
||||
|
||||
box.Checked += delegate { this.IsChecked = true; }; |
||||
box.Unchecked += delegate { this.IsChecked = false; }; |
||||
|
||||
return box; |
||||
} |
||||
} |
||||
} |
@ -0,0 +1,60 @@
@@ -0,0 +1,60 @@
|
||||
// <file>
|
||||
// <copyright see="prj:///doc/copyright.txt"/>
|
||||
// <license see="prj:///doc/license.txt"/>
|
||||
// <owner name="Siegfried Pammer" email="siegfriedpammer@gmail.com" />
|
||||
// <version>$Revision$</version>
|
||||
// </file>
|
||||
|
||||
using System; |
||||
using System.Linq; |
||||
using System.Windows.Forms; |
||||
using ICSharpCode.Core; |
||||
using ICSharpCode.SharpDevelop; |
||||
using ICSharpCode.SharpDevelop.Dom; |
||||
using ICSharpCode.SharpDevelop.Dom.Refactoring; |
||||
using ICSharpCode.SharpDevelop.Editor; |
||||
using ICSharpCode.SharpDevelop.Refactoring; |
||||
using SharpRefactoring.Gui; |
||||
|
||||
namespace SharpRefactoring |
||||
{ |
||||
/// <summary>
|
||||
/// Description of OverrideToStringMethodCommand
|
||||
/// </summary>
|
||||
public class OverrideToStringMethodCommand : AbstractRefactoringCommand |
||||
{ |
||||
protected override void Run(ITextEditor textEditor, RefactoringProvider provider) |
||||
{ |
||||
IEditorUIService uiService = textEditor.GetService(typeof(IEditorUIService)) as IEditorUIService; |
||||
|
||||
if (uiService == null) |
||||
return; |
||||
|
||||
ParseInformation parseInfo = ParserService.GetParseInformation(textEditor.FileName); |
||||
|
||||
if (parseInfo == null) |
||||
return; |
||||
|
||||
CodeGenerator generator = parseInfo.CompilationUnit.Language.CodeGenerator; |
||||
IClass current = parseInfo.CompilationUnit.GetInnermostClass(textEditor.Caret.Line, textEditor.Caret.Column); |
||||
|
||||
if (current == null) |
||||
return; |
||||
|
||||
ITextAnchor anchor = textEditor.Document.CreateAnchor(textEditor.Caret.Offset); |
||||
anchor.MovementType = AnchorMovementType.AfterInsertion; |
||||
|
||||
textEditor.Document.Insert(anchor.Offset, "public override ToString()\n{\n\t"); |
||||
|
||||
ITextAnchor parameterListAnchor = textEditor.Document.CreateAnchor(anchor.Offset - ")\n{\n\t".Length); |
||||
parameterListAnchor.SurviveDeletion = true; |
||||
parameterListAnchor.MovementType = AnchorMovementType.AfterInsertion; |
||||
|
||||
textEditor.Document.Insert(anchor.Offset + 1, "\n\t\n}\n"); |
||||
|
||||
InlineRefactorDialog dialog = new OverrideToStringMethodDialog(textEditor, anchor, parameterListAnchor, current.Fields); |
||||
|
||||
dialog.Element = uiService.CreateInlineUIElement(anchor, dialog); |
||||
} |
||||
} |
||||
} |
@ -0,0 +1,23 @@
@@ -0,0 +1,23 @@
|
||||
// <file>
|
||||
// <copyright see="prj:///doc/copyright.txt"/>
|
||||
// <license see="prj:///doc/license.txt"/>
|
||||
// <owner name="Siegfried Pammer" email="siegfriedpammer@gmail.com" />
|
||||
// <version>$Revision$</version>
|
||||
// </file>
|
||||
|
||||
using System; |
||||
using System.Windows; |
||||
using System.Windows.Controls; |
||||
|
||||
namespace ICSharpCode.SharpDevelop.Editor |
||||
{ |
||||
public interface IEditorUIService |
||||
{ |
||||
IInlineUIElement CreateInlineUIElement(ITextAnchor position, UIElement element); |
||||
} |
||||
|
||||
public interface IInlineUIElement |
||||
{ |
||||
void Remove(); |
||||
} |
||||
} |
@ -0,0 +1,60 @@
@@ -0,0 +1,60 @@
|
||||
// <file>
|
||||
// <copyright see="prj:///doc/copyright.txt"/>
|
||||
// <license see="prj:///doc/license.txt"/>
|
||||
// <owner name="Daniel Grunwald" email="daniel@danielgrunwald.de"/>
|
||||
// <version>$Revision: 4961 $</version>
|
||||
// </file>
|
||||
|
||||
using System; |
||||
using System.Collections.Generic; |
||||
using System.Diagnostics; |
||||
using System.Linq; |
||||
|
||||
namespace ICSharpCode.SharpDevelop.Dom |
||||
{ |
||||
public class ParameterListComparer : IEqualityComparer<IMethod> |
||||
{ |
||||
public bool Equals(IMethod x, IMethod y) |
||||
{ |
||||
if (GetHashCode(x) != GetHashCode(y)) |
||||
return false; |
||||
var paramsX = x.Parameters; |
||||
var paramsY = y.Parameters; |
||||
if (paramsX.Count != paramsY.Count) |
||||
return false; |
||||
if (x.TypeParameters.Count != y.TypeParameters.Count) |
||||
return false; |
||||
for (int i = 0; i < paramsX.Count; i++) { |
||||
IParameter px = paramsX[i]; |
||||
IParameter py = paramsY[i]; |
||||
if ((px.IsOut || px.IsRef) != (py.IsOut || py.IsRef)) |
||||
return false; |
||||
if (!object.Equals(px.ReturnType, py.ReturnType)) |
||||
return false; |
||||
} |
||||
return true; |
||||
} |
||||
|
||||
Dictionary<IMethod, int> cachedHashes = new Dictionary<IMethod, int>(); |
||||
|
||||
public int GetHashCode(IMethod obj) |
||||
{ |
||||
int hashCode; |
||||
if (cachedHashes.TryGetValue(obj, out hashCode)) |
||||
return hashCode; |
||||
hashCode = obj.TypeParameters.Count; |
||||
unchecked { |
||||
foreach (IParameter p in obj.Parameters) { |
||||
hashCode *= 1000000579; |
||||
if (p.IsOut || p.IsRef) |
||||
hashCode += 1; |
||||
if (p.ReturnType != null) { |
||||
hashCode += p.ReturnType.GetHashCode(); |
||||
} |
||||
} |
||||
} |
||||
cachedHashes[obj] = hashCode; |
||||
return hashCode; |
||||
} |
||||
} |
||||
} |
@ -0,0 +1,43 @@
@@ -0,0 +1,43 @@
|
||||
// <file>
|
||||
// <copyright see="prj:///doc/copyright.txt"/>
|
||||
// <license see="prj:///doc/license.txt"/>
|
||||
// <owner name="Daniel Grunwald" email="daniel@danielgrunwald.de"/>
|
||||
// <version>$Revision: 4961 $</version>
|
||||
// </file>
|
||||
|
||||
using System; |
||||
using System.Collections.Generic; |
||||
using System.Diagnostics; |
||||
using System.Linq; |
||||
|
||||
namespace ICSharpCode.SharpDevelop.Dom |
||||
{ |
||||
public class SignatureComparer : IEqualityComparer<IMember> |
||||
{ |
||||
ParameterListComparer parameterListComparer = new ParameterListComparer(); |
||||
|
||||
public bool Equals(IMember x, IMember y) |
||||
{ |
||||
if (x.Type != y.Type) |
||||
return false; |
||||
|
||||
if (x.Name != y.Name) |
||||
return false; |
||||
|
||||
if (x is IMethod && y is IMethod) |
||||
return parameterListComparer.Equals(x as IMethod, y as IMethod); |
||||
|
||||
return true; |
||||
} |
||||
|
||||
public int GetHashCode(IMember obj) |
||||
{ |
||||
int hashCode = obj.Name.GetHashCode(); |
||||
|
||||
if (obj is IMethod) |
||||
hashCode ^= parameterListComparer.GetHashCode(obj as IMethod); |
||||
|
||||
return hashCode; |
||||
} |
||||
} |
||||
} |
Loading…
Reference in new issue