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));
+ }
+ }
}
}