From 215fa3be973b545bbad95aa771f9a7b569bc223c Mon Sep 17 00:00:00 2001 From: Andreas Weizel Date: Wed, 11 Sep 2013 15:20:11 +0200 Subject: [PATCH] First implementation of "Open in Class Browser" command in entity context menu. --- .../OutputVisitor/CSharpAmbience.cs | 2 +- .../Dom/ClassBrowser/ClassBrowserTreeView.cs | 113 ++++++++++++++++++ .../Project/Dom/ClassBrowser/IClassBrowser.cs | 2 + .../Project/Dom/ModelCollectionTreeNode.cs | 25 ++++ .../Project/ICSharpCode.SharpDevelop.addin | 8 ++ .../Dom/ClassBrowser/ClassBrowserPad.cs | 8 ++ .../SharpDevelop/Dom/ClassBrowser/Commands.cs | 17 +++ 7 files changed, 174 insertions(+), 1 deletion(-) diff --git a/src/Libraries/NRefactory/ICSharpCode.NRefactory.CSharp/OutputVisitor/CSharpAmbience.cs b/src/Libraries/NRefactory/ICSharpCode.NRefactory.CSharp/OutputVisitor/CSharpAmbience.cs index ee21e19b2a..180375bf66 100644 --- a/src/Libraries/NRefactory/ICSharpCode.NRefactory.CSharp/OutputVisitor/CSharpAmbience.cs +++ b/src/Libraries/NRefactory/ICSharpCode.NRefactory.CSharp/OutputVisitor/CSharpAmbience.cs @@ -182,7 +182,7 @@ namespace ICSharpCode.NRefactory.CSharp { TypeSystemAstBuilder astBuilder = CreateAstBuilder(); EntityDeclaration node = astBuilder.ConvertEntity(member); - TypeDeclaration typeDecl = (TypeDeclaration)astBuilder.ConvertEntity(member.DeclaringTypeDefinition); +// TypeDeclaration typeDecl = (TypeDeclaration)astBuilder.ConvertEntity(member.DeclaringTypeDefinition); if ((ConversionFlags & ConversionFlags.ShowDeclaringType) == ConversionFlags.ShowDeclaringType) { ConvertType(member.DeclaringType, writer, formattingPolicy); writer.WriteToken(Roles.Dot, "."); diff --git a/src/Main/Base/Project/Dom/ClassBrowser/ClassBrowserTreeView.cs b/src/Main/Base/Project/Dom/ClassBrowser/ClassBrowserTreeView.cs index 317ca39bf9..d67600f816 100644 --- a/src/Main/Base/Project/Dom/ClassBrowser/ClassBrowserTreeView.cs +++ b/src/Main/Base/Project/Dom/ClassBrowser/ClassBrowserTreeView.cs @@ -2,10 +2,13 @@ // This code is distributed under the GNU LGPL (for details please see \doc\license.txt) using System; +using System.Linq; using System.Collections.Generic; using System.Windows.Controls; using ICSharpCode.Core; +using ICSharpCode.NRefactory.TypeSystem; using ICSharpCode.TreeView; +using ICSharpCode.SharpDevelop.Project; namespace ICSharpCode.SharpDevelop.Dom.ClassBrowser { @@ -57,6 +60,116 @@ namespace ICSharpCode.SharpDevelop.Dom.ClassBrowser treeNode.ShowContextMenu(); } } + + public bool GoToEntity(IEntity entity) + { + // Try to find assembly in workspace + var entityAssembly = entity.ParentAssembly; + if (entityAssembly != null) { + ITypeDefinition entityType = null; + if (entity is ITypeDefinition) { + entityType = (ITypeDefinition) entity; + } else { + entityType = entity.DeclaringTypeDefinition; + } + + SharpTreeNodeCollection namespaceChildren = null; + var root = this.Root as WorkspaceTreeNode; + + // Try to find assembly of passed entity among open projects in solution + var solutionTreeNode = this.Root.Children.OfType().FirstOrDefault(); + if (solutionTreeNode != null) { + // Ensure that we have children + solutionTreeNode.EnsureLazyChildren(); + + var projectTreeNode = solutionTreeNode.Children.FirstOrDefault( + node => { + if (node is ProjectTreeNode) { + var treeNode = (ProjectTreeNode) node; + if (node.Model is IProject) { + var projectModel = (IProject) node.Model; + // TODO Use full name here! + return projectModel.AssemblyModel.AssemblyName == entityAssembly.AssemblyName; + } + } + + return false; + }); + if (projectTreeNode != null) { + projectTreeNode.EnsureLazyChildren(); + namespaceChildren = projectTreeNode.Children; + } + } + + if (namespaceChildren == null) { + // Try to find assembly of passed entity among additional assemblies + var assemblyTreeNode = this.Root.Children.FirstOrDefault( + node => { + if (node is AssemblyTreeNode) { + var asmTreeNode = (AssemblyTreeNode) node; + if (node.Model is IAssemblyModel) { + var asmModel = (IAssemblyModel) node.Model; + // TODO Use full name here! + return asmModel.AssemblyName == entityAssembly.AssemblyName; + } + } + + return false; + }); + if (assemblyTreeNode != null) { + assemblyTreeNode.EnsureLazyChildren(); + namespaceChildren = assemblyTreeNode.Children; + } + } + + // TODO Add assembly to workspace, if not available in ClassBrowser + + if (namespaceChildren != null) { + var nsTreeNode = namespaceChildren.FirstOrDefault( + node => + (node is NamespaceTreeNode) + && (((NamespaceTreeNode) node).Model is INamespaceModel) + && (((INamespaceModel) ((NamespaceTreeNode) node).Model).FullName == entityType.Namespace) + ) as ModelCollectionTreeNode; + + if (nsTreeNode != null) { + // Ensure that we have children + nsTreeNode.EnsureLazyChildren(); + + // Search in namespace node recursively + var foundEntityNode = nsTreeNode.FindChildNodeRecursively( + node => { + var treeNode = node as ModelCollectionTreeNode; + if (treeNode != null) { + if ((entity is ITypeDefinition) && (treeNode.Model is ITypeDefinitionModel)) { + // Compare directly with type + var modelFullTypeName = ((ITypeDefinitionModel) treeNode.Model).FullTypeName; + return modelFullTypeName == entityType.FullTypeName; + } + if ((entity is IMember) && (treeNode.Model is IMemberModel)) { + // Compare parent types and member names + IMemberModel memberModel = (IMemberModel) treeNode.Model; + IMember member = (IMember) entity; + return (member.DeclaringType.FullName == entityType.FullName) + && (member.Name == memberModel.Name) + && (member.SymbolKind == memberModel.SymbolKind); + } + } + + return false; + }); + + if (foundEntityNode != null) { + this.FocusNode(foundEntityNode); + this.SelectedItem = foundEntityNode; + return true; + } + } + } + } + + return false; + } } public interface IClassBrowserTreeView : IClassBrowser diff --git a/src/Main/Base/Project/Dom/ClassBrowser/IClassBrowser.cs b/src/Main/Base/Project/Dom/ClassBrowser/IClassBrowser.cs index 031ada059a..fcee6112ea 100644 --- a/src/Main/Base/Project/Dom/ClassBrowser/IClassBrowser.cs +++ b/src/Main/Base/Project/Dom/ClassBrowser/IClassBrowser.cs @@ -4,6 +4,7 @@ using System; using System.Collections.Generic; using ICSharpCode.Core; +using ICSharpCode.NRefactory.TypeSystem; namespace ICSharpCode.SharpDevelop.Dom.ClassBrowser { @@ -13,5 +14,6 @@ namespace ICSharpCode.SharpDevelop.Dom.ClassBrowser IAssemblyList UnpinnedAssemblies { get; set; } ICollection AssemblyLists { get; } IAssemblyModel FindAssemblyModel(FileName fileName); + bool GoToEntity(IEntity entity); } } diff --git a/src/Main/Base/Project/Dom/ModelCollectionTreeNode.cs b/src/Main/Base/Project/Dom/ModelCollectionTreeNode.cs index 3bbe23f81c..3aa1f0565d 100644 --- a/src/Main/Base/Project/Dom/ModelCollectionTreeNode.cs +++ b/src/Main/Base/Project/Dom/ModelCollectionTreeNode.cs @@ -104,6 +104,31 @@ namespace ICSharpCode.SharpDevelop.Dom Children.Clear(); LazyLoading = true; } + + public SharpTreeNode FindChildNodeRecursively(Func predicate) + { + if (predicate == null) + return null; + + SharpTreeNode foundNode = null; + foreach (var child in Children) { + if (predicate(child)) { + // This is our node! + foundNode = child; + break; + } + + // Search in all children of this node + child.EnsureLazyChildren(); + if (child is ModelCollectionTreeNode) { + foundNode = ((ModelCollectionTreeNode) child).FindChildNodeRecursively(predicate); + if (foundNode != null) + break; + } + } + + return foundNode; + } #endregion } diff --git a/src/Main/Base/Project/ICSharpCode.SharpDevelop.addin b/src/Main/Base/Project/ICSharpCode.SharpDevelop.addin index cdd9bf4c90..ba9be7dfd3 100755 --- a/src/Main/Base/Project/ICSharpCode.SharpDevelop.addin +++ b/src/Main/Base/Project/ICSharpCode.SharpDevelop.addin @@ -1005,6 +1005,14 @@ class = "ICSharpCode.SharpDevelop.Dom.ClassBrowser.RemoveAssemblyCommand"/> + + + + diff --git a/src/Main/SharpDevelop/Dom/ClassBrowser/ClassBrowserPad.cs b/src/Main/SharpDevelop/Dom/ClassBrowser/ClassBrowserPad.cs index 5be1332d33..05a28b2277 100644 --- a/src/Main/SharpDevelop/Dom/ClassBrowser/ClassBrowserPad.cs +++ b/src/Main/SharpDevelop/Dom/ClassBrowser/ClassBrowserPad.cs @@ -150,6 +150,14 @@ namespace ICSharpCode.SharpDevelop.Dom.ClassBrowser get { return treeView; } } + public bool GoToEntity(IEntity entity) + { + // Activate the pad + this.BringToFront(); + // Look for entity in tree + return treeView.GoToEntity(entity); + } + void ProjectServiceCurrentSolutionChanged(object sender, EventArgs e) { foreach (var node in treeView.AssemblyLists.OfType().ToArray()) diff --git a/src/Main/SharpDevelop/Dom/ClassBrowser/Commands.cs b/src/Main/SharpDevelop/Dom/ClassBrowser/Commands.cs index 5caa8a5720..f8008ed141 100644 --- a/src/Main/SharpDevelop/Dom/ClassBrowser/Commands.cs +++ b/src/Main/SharpDevelop/Dom/ClassBrowser/Commands.cs @@ -5,7 +5,9 @@ using System; using System.Diagnostics; using System.IO; using System.Linq; +using ICSharpCode.NRefactory.Semantics; using ICSharpCode.SharpDevelop.Debugging; +using ICSharpCode.SharpDevelop.Editor.Commands; using Microsoft.Win32; namespace ICSharpCode.SharpDevelop.Dom.ClassBrowser @@ -98,4 +100,19 @@ namespace ICSharpCode.SharpDevelop.Dom.ClassBrowser }); } } + + /// + /// OpenInClassBrowserCommand. + /// + class OpenInClassBrowserCommand : ResolveResultMenuCommand + { + public override void Run(ResolveResult symbol) + { + var classBrowser = SD.GetService(); + var entity = GetEntity(symbol); + if ((classBrowser != null) && (entity != null)) { + classBrowser.GoToEntity(entity); + } + } + } }