From 8b55c77771990cf08d6a9046416f15094916fb45 Mon Sep 17 00:00:00 2001 From: Andreas Weizel Date: Thu, 18 Jul 2013 00:41:25 +0200 Subject: [PATCH] Adding AddIns to ClassBrowser, persistence and restoring of ClassBrowser workspace in config. --- src/Main/Base/Project/Dom/IAssemblyModel.cs | 11 ++ .../Base/Project/Dom/IEntityModelContext.cs | 18 +++ src/Main/SharpDevelop/Dom/AssemblyModel.cs | 6 + .../Dom/ClassBrowser/ClassBrowserPad.cs | 148 +++++++++++++++++- .../ClassBrowserTreeNodesFactory.cs | 4 + .../Dom/ClassBrowser/OpenAssemblyCommand.cs | 16 +- 6 files changed, 201 insertions(+), 2 deletions(-) diff --git a/src/Main/Base/Project/Dom/IAssemblyModel.cs b/src/Main/Base/Project/Dom/IAssemblyModel.cs index 11a081dd01..f3df5c2589 100644 --- a/src/Main/Base/Project/Dom/IAssemblyModel.cs +++ b/src/Main/Base/Project/Dom/IAssemblyModel.cs @@ -42,6 +42,11 @@ namespace ICSharpCode.SharpDevelop.Dom /// This always is the namespace without a name - it's unrelated to the 'root namespace' project setting. /// INamespaceModel RootNamespace { get; } + + /// + /// Gets the of this assembly model. + /// + IEntityModelContext Context { get; } } /// @@ -92,6 +97,12 @@ namespace ICSharpCode.SharpDevelop.Dom public INamespaceModel RootNamespace { get { return EmptyNamespaceModel.Instance; } } + + public IEntityModelContext Context { + get { + return null; + } + } } } diff --git a/src/Main/Base/Project/Dom/IEntityModelContext.cs b/src/Main/Base/Project/Dom/IEntityModelContext.cs index 5fe67f32e4..69295ef7b3 100644 --- a/src/Main/Base/Project/Dom/IEntityModelContext.cs +++ b/src/Main/Base/Project/Dom/IEntityModelContext.cs @@ -34,6 +34,16 @@ namespace ICSharpCode.SharpDevelop.Dom /// Returns true if part1 is considered a better candidate for the primary part than part2. /// bool IsBetterPart(IUnresolvedTypeDefinition part1, IUnresolvedTypeDefinition part2); + + /// + /// Short name of current assembly. + /// + string AssemblyName { get; } + + /// + /// Full path and file name of the assembly. Output assembly for projects. + /// + string Location { get; } } public class ProjectEntityModelContext : IEntityModelContext @@ -53,6 +63,10 @@ namespace ICSharpCode.SharpDevelop.Dom get { return project.AssemblyName; } } + public string Location { + get { return project.OutputAssemblyFullPath; } + } + public IProject Project { get { return project; } } @@ -88,6 +102,10 @@ namespace ICSharpCode.SharpDevelop.Dom get { return mainAssembly.AssemblyName; } } + public string Location { + get { return mainAssembly.Location; } + } + public ICompilation GetCompilation() { return compilation; diff --git a/src/Main/SharpDevelop/Dom/AssemblyModel.cs b/src/Main/SharpDevelop/Dom/AssemblyModel.cs index 1cecb2ee50..b10684186e 100644 --- a/src/Main/SharpDevelop/Dom/AssemblyModel.cs +++ b/src/Main/SharpDevelop/Dom/AssemblyModel.cs @@ -50,6 +50,12 @@ namespace ICSharpCode.SharpDevelop.Dom } } + public IEntityModelContext Context { + get { + return context; + } + } + public void Update(IUnresolvedFile oldFile, IUnresolvedFile newFile) { IList old = EmptyList.Instance; diff --git a/src/Main/SharpDevelop/Dom/ClassBrowser/ClassBrowserPad.cs b/src/Main/SharpDevelop/Dom/ClassBrowser/ClassBrowserPad.cs index 871bc7a139..168e9f1a59 100644 --- a/src/Main/SharpDevelop/Dom/ClassBrowser/ClassBrowserPad.cs +++ b/src/Main/SharpDevelop/Dom/ClassBrowser/ClassBrowserPad.cs @@ -7,12 +7,26 @@ using System.Collections.Generic; using System.Diagnostics; using System.Windows.Controls; using ICSharpCode.Core.Presentation; +using ICSharpCode.NRefactory; +using ICSharpCode.NRefactory.TypeSystem; using ICSharpCode.TreeView; using ICSharpCode.SharpDevelop.Project; using ICSharpCode.SharpDevelop.Workbench; namespace ICSharpCode.SharpDevelop.Dom.ClassBrowser { + public class PersistedWorkspace + { + public PersistedWorkspace() + { + AssemblyFiles = new List(); + } + + public string Name { get; set; } + public List AssemblyFiles { get; set; } + public bool IsActive { get; set; } + } + class ClassBrowserPad : AbstractPadContent, IClassBrowser { #region IClassBrowser implementation @@ -25,13 +39,19 @@ namespace ICSharpCode.SharpDevelop.Dom.ClassBrowser get { return treeView.AssemblyList; } set { treeView.AssemblyList = value; } } - + #endregion + + const string PersistedWorkspaceSetting = "ClassBrowser.Workspaces"; + const string DefaultWorkspaceName = ""; IProjectService projectService; ClassBrowserTreeView treeView; DockPanel panel; ToolBar toolBar; + + List persistedWorkspaces; + PersistedWorkspace activeWorkspace; public ClassBrowserPad() : this(SD.GetRequiredService()) @@ -53,6 +73,9 @@ namespace ICSharpCode.SharpDevelop.Dom.ClassBrowser //treeView.ContextMenu = CreateContextMenu("/SharpDevelop/Pads/UnitTestsPad/ContextMenu"); projectService.CurrentSolutionChanged += ProjectServiceCurrentSolutionChanged; ProjectServiceCurrentSolutionChanged(null, null); + + // Load workspaces from configuration + LoadWorkspaces(); } public override void Dispose() @@ -77,6 +100,26 @@ namespace ICSharpCode.SharpDevelop.Dom.ClassBrowser treeView.SpecialNodes.Add(new SolutionTreeNode(projectService.CurrentSolution)); } + void AssemblyListCollectionChanged(IReadOnlyCollection removedItems, IReadOnlyCollection addedItems) + { + foreach (var assembly in addedItems) { + // Add this assembly to current workspace + if (activeWorkspace != null) { + activeWorkspace.AssemblyFiles.Add(assembly.Context.Location); + } + } + + foreach (var assembly in removedItems) { + // Add this assembly to current workspace + if (activeWorkspace != null) { + activeWorkspace.AssemblyFiles.Remove(assembly.Context.Location); + } + } + + // Update workspace list in configuration + SaveWorkspaces(); + } + /// /// Virtual method so we can override this method and return /// a dummy ToolBar when testing. @@ -96,5 +139,108 @@ namespace ICSharpCode.SharpDevelop.Dom.ClassBrowser Debug.Assert(treeView != null); return MenuService.CreateContextMenu(treeView, name); } + + /// + /// Loads persisted workspaces from configuration. + /// + void LoadWorkspaces() + { + persistedWorkspaces = SD.PropertyService.GetList(PersistedWorkspaceSetting).ToList(); + if (!persistedWorkspaces.Any()) + { + // Add at least default workspace + persistedWorkspaces = new List(); + persistedWorkspaces.Add(new PersistedWorkspace() + { + Name = DefaultWorkspaceName + }); + } + + // Load all assemblies (for now always from default workspace) + PersistedWorkspace defaultWorkspace = persistedWorkspaces.FirstOrDefault(w => w.Name == DefaultWorkspaceName); + ActivateWorkspace(defaultWorkspace); + } + + /// + /// Stores currently saved workspaces in configuration. + /// + void SaveWorkspaces() + { + SD.PropertyService.SetList(PersistedWorkspaceSetting, persistedWorkspaces); + } + + public static IAssemblyModel CreateAssemblyModelFromFile(string fileName) + { + // TODO References? + + var loader = new CecilLoader(); + loader.IncludeInternalMembers = true; + loader.LazyLoad = true; + var assembly = loader.LoadAssemblyFile(fileName); + + IEntityModelContext context = new AssemblyEntityModelContext(assembly); + IAssemblyModel model = SD.GetRequiredService().CreateAssemblyModel(context); + + if (model is IUpdateableAssemblyModel) { + ((IUpdateableAssemblyModel)model).Update(EmptyList.Instance, assembly.TopLevelTypeDefinitions.ToList()); + ((IUpdateableAssemblyModel) model).AssemblyName = assembly.AssemblyName; + } + return model; + } + + void AppendAssemblyFileToList(string assemblyFile) + { + IAssemblyModel assemblyModel = CreateAssemblyModelFromFile(assemblyFile); + if (assemblyModel != null) { + AssemblyList.Assemblies.Add(assemblyModel); + } else { + // TODO Throw exception? + + } + } + + /// + /// Activates the specified workspace. + /// + void ActivateWorkspace(PersistedWorkspace workspace) + { + // Update the activation flags in workspace list + foreach (var workspaceElement in persistedWorkspaces) { + workspaceElement.IsActive = (workspaceElement == workspace); + } + + UpdateActiveWorkspace(); + } + + /// + /// Updates active workspace and AssemblyList according to flags. + /// + void UpdateActiveWorkspace() + { + if ((AssemblyList != null) && (activeWorkspace != null)) { + // Temporarily detach from event handler + AssemblyList.Assemblies.CollectionChanged -= AssemblyListCollectionChanged; + } + + activeWorkspace = persistedWorkspaces.FirstOrDefault(w => w.IsActive); + if (activeWorkspace == null) { + // If no workspace is active, activate default + var defaultWorkspace = persistedWorkspaces.FirstOrDefault(w => w.Name == DefaultWorkspaceName); + activeWorkspace = defaultWorkspace; + defaultWorkspace.IsActive = true; + } + + AssemblyList.Assemblies.Clear(); + if (activeWorkspace != null) { + foreach (string assemblyFile in activeWorkspace.AssemblyFiles) { + AppendAssemblyFileToList(assemblyFile); + } + } + + // Attach to event handler, again. + if (AssemblyList != null) { + AssemblyList.Assemblies.CollectionChanged += AssemblyListCollectionChanged; + } + } } } diff --git a/src/Main/SharpDevelop/Dom/ClassBrowser/ClassBrowserTreeNodesFactory.cs b/src/Main/SharpDevelop/Dom/ClassBrowser/ClassBrowserTreeNodesFactory.cs index c85f22786a..23fe3fcb2f 100644 --- a/src/Main/SharpDevelop/Dom/ClassBrowser/ClassBrowserTreeNodesFactory.cs +++ b/src/Main/SharpDevelop/Dom/ClassBrowser/ClassBrowserTreeNodesFactory.cs @@ -21,6 +21,8 @@ namespace ICSharpCode.SharpDevelop.Dom.ClassBrowser return typeof(ITypeDefinitionModel); if (model is IMemberModel) return typeof(IMemberModel); + if (model is IAssemblyModel) + return typeof(IAssemblyModel); return null; } @@ -36,6 +38,8 @@ namespace ICSharpCode.SharpDevelop.Dom.ClassBrowser return new TypeDefinitionTreeNode((ITypeDefinitionModel)model); if (model is IMemberModel) return new MemberTreeNode((IMemberModel)model); + if (model is IAssemblyModel) + return new AssemblyTreeNode((IAssemblyModel) model); return null; } } diff --git a/src/Main/SharpDevelop/Dom/ClassBrowser/OpenAssemblyCommand.cs b/src/Main/SharpDevelop/Dom/ClassBrowser/OpenAssemblyCommand.cs index 59851280c6..ae67f21e5e 100644 --- a/src/Main/SharpDevelop/Dom/ClassBrowser/OpenAssemblyCommand.cs +++ b/src/Main/SharpDevelop/Dom/ClassBrowser/OpenAssemblyCommand.cs @@ -2,6 +2,10 @@ // This code is distributed under the GNU LGPL (for details please see \doc\license.txt) using System; +using System.Linq; +using ICSharpCode.NRefactory; +using ICSharpCode.NRefactory.TypeSystem; +using Microsoft.Win32; namespace ICSharpCode.SharpDevelop.Dom.ClassBrowser { @@ -12,7 +16,17 @@ namespace ICSharpCode.SharpDevelop.Dom.ClassBrowser { public override void Execute(object parameter) { - throw new NotImplementedException(); + var classBrowser = SD.GetService(); + if (classBrowser != null) { + OpenFileDialog openFileDialog = new OpenFileDialog(); + openFileDialog.Filter = "Assembly files (*.exe, *.dll)|*.exe;*.dll"; + openFileDialog.CheckFileExists = true; + openFileDialog.CheckPathExists = true; + if (openFileDialog.ShowDialog() ?? false) + { + classBrowser.AssemblyList.Assemblies.Add(ClassBrowserPad.CreateAssemblyModelFromFile(openFileDialog.FileName)); + } + } } }