diff --git a/src/AddIns/Debugger/Debugger.AddIn/Debugger.AddIn.addin b/src/AddIns/Debugger/Debugger.AddIn/Debugger.AddIn.addin index c7143dbb8d..42f941260f 100644 --- a/src/AddIns/Debugger/Debugger.AddIn/Debugger.AddIn.addin +++ b/src/AddIns/Debugger/Debugger.AddIn/Debugger.AddIn.addin @@ -149,4 +149,8 @@ + + + + diff --git a/src/AddIns/Debugger/Debugger.AddIn/Debugger.AddIn.csproj b/src/AddIns/Debugger/Debugger.AddIn/Debugger.AddIn.csproj index ab07982060..147c39d4e5 100644 --- a/src/AddIns/Debugger/Debugger.AddIn/Debugger.AddIn.csproj +++ b/src/AddIns/Debugger/Debugger.AddIn/Debugger.AddIn.csproj @@ -111,6 +111,7 @@ Code + diff --git a/src/AddIns/Debugger/Debugger.AddIn/Pads/ClassBrowserSupport.cs b/src/AddIns/Debugger/Debugger.AddIn/Pads/ClassBrowserSupport.cs new file mode 100644 index 0000000000..d4b76afdaf --- /dev/null +++ b/src/AddIns/Debugger/Debugger.AddIn/Pads/ClassBrowserSupport.cs @@ -0,0 +1,149 @@ +// 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.IO; +using Debugger; +using ICSharpCode.NRefactory; +using ICSharpCode.NRefactory.TypeSystem; +using ICSharpCode.SharpDevelop.Dom; +using ICSharpCode.SharpDevelop.Dom.ClassBrowser; +using System.Linq; + +namespace ICSharpCode.SharpDevelop.Gui.Pads +{ + /// + /// Description of ClassBrowserSupport. + /// + public static class ClassBrowserSupport + { + public static void Attach(Debugger.Process process) + { + var classBrowser = SD.GetService(); + classBrowser.SpecialNodes.Add(new DebuggerProcessTreeNode(process)); + } + + public static void Detach(Debugger.Process process) + { + var classBrowser = SD.GetService(); + var nodes = classBrowser.SpecialNodes + .Where(n => n.Model == process) + .ToArray(); + foreach (var node in nodes) { + classBrowser.SpecialNodes.Remove(node); + } + } + } + + class DebuggerTreeNodesFactory : ITreeNodeFactory + { + public Type GetSupportedType(object model) + { + if (model is Debugger.Process) + return typeof(Debugger.Process); + if (model is Debugger.Module) + return typeof(Debugger.Module); + return null; + } + + public ICSharpCode.TreeView.SharpTreeNode CreateTreeNode(object model) + { + if (model is Debugger.Process) + return new DebuggerProcessTreeNode((Debugger.Process)model); + if (model is Debugger.Module) + return new DebuggerModuleTreeNode((Debugger.Module)model); + return null; + } + } + + class DebuggerProcessTreeNode : ModelCollectionTreeNode + { + Debugger.Process process; + IMutableModelCollection modules; + + public DebuggerProcessTreeNode(Debugger.Process process) + { + if (process == null) + throw new ArgumentNullException("process"); + this.process = process; + this.modules = new SimpleModelCollection(this.process.Modules); + this.process.ModuleLoaded += ModuleLoaded; + this.process.ModuleUnloaded += ModuleUnloaded; + } + + void ModuleLoaded(object sender, ModuleEventArgs e) + { + modules.Add(e.Module); + } + + void ModuleUnloaded(object sender, ModuleEventArgs e) + { + modules.Remove(e.Module); + } + + protected override object GetModel() + { + return process; + } + + protected override IModelCollection ModelChildren { + get { + return modules; + } + } + + protected override System.Collections.Generic.IComparer NodeComparer { + get { + return NodeTextComparer; + } + } + + public override object Text { + get { + return Path.GetFileName(process.Filename); + } + } + + public override object Icon { + get { + return IconService.GetImageSource("Icons.16x16.Debug.Start"); + } + } + } + + class DebuggerModuleTreeNode : AssemblyTreeNode + { + Debugger.Module module; + + public DebuggerModuleTreeNode(Module module) + : base(CreateAssemblyModel(module)) + { + if (module == null) + throw new ArgumentNullException("module"); + this.module = module; + } + + public override object Icon { + get { + return IconService.GetImageSource("PadIcons.LoadedModules"); + } + } + + public override object Text { + get { + return module.Name; + } + } + + static IAssemblyModel CreateAssemblyModel(Module module) + { + // references?? + IEntityModelContext context = new AssemblyEntityModelContext(module.Assembly.UnresolvedAssembly); + IAssemblyModel model = SD.GetRequiredService().CreateAssemblyModel(context); + if (model is IUpdateableAssemblyModel) { + ((IUpdateableAssemblyModel)model).Update(EmptyList.Instance, module.Assembly.TopLevelTypeDefinitions.SelectMany(td => td.Parts).ToList()); + } + return model; + } + } +} diff --git a/src/AddIns/Debugger/Debugger.AddIn/Service/WindowsDebugger.cs b/src/AddIns/Debugger/Debugger.AddIn/Service/WindowsDebugger.cs index 8433a12fec..77ad2ab3bb 100644 --- a/src/AddIns/Debugger/Debugger.AddIn/Service/WindowsDebugger.cs +++ b/src/AddIns/Debugger/Debugger.AddIn/Service/WindowsDebugger.cs @@ -10,6 +10,7 @@ using System.Linq; using System.Runtime.InteropServices; using System.Windows.Forms; using Debugger; +using ICSharpCode.SharpDevelop.Gui.Pads; using Debugger.AddIn; using Debugger.AddIn.Tooltips; using Debugger.AddIn.TreeModel; @@ -232,6 +233,7 @@ namespace ICSharpCode.SharpDevelop.Services public void Detach() { + ClassBrowserSupport.Detach(CurrentProcess); CurrentDebugger.Detach(); } @@ -438,6 +440,7 @@ namespace ICSharpCode.SharpDevelop.Services CurrentProcess.Paused += debuggedProcess_DebuggingPaused; CurrentProcess.Resumed += debuggedProcess_DebuggingResumed; CurrentProcess.Exited += (s, e) => debugger_ProcessExited(); + ClassBrowserSupport.Attach(CurrentProcess); UpdateBreakpointIcons(); } @@ -448,6 +451,7 @@ namespace ICSharpCode.SharpDevelop.Services DebugStopped(this, EventArgs.Empty); } + ClassBrowserSupport.Detach(CurrentProcess); CurrentProcess = null; CurrentThread = null; CurrentStackFrame = null; diff --git a/src/Main/Base/Project/Dom/ClassBrowser/AssemblyTreeNode.cs b/src/Main/Base/Project/Dom/ClassBrowser/AssemblyTreeNode.cs index b07618baf4..28e67cd2db 100644 --- a/src/Main/Base/Project/Dom/ClassBrowser/AssemblyTreeNode.cs +++ b/src/Main/Base/Project/Dom/ClassBrowser/AssemblyTreeNode.cs @@ -34,6 +34,18 @@ namespace ICSharpCode.SharpDevelop.Dom.ClassBrowser return model.Namespaces; } } + + public override object Text { + get { + return model.AssemblyName; + } + } + + public override object Icon { + get { + return base.Icon; + } + } } } diff --git a/src/Main/Base/Project/Dom/IAssemblyModel.cs b/src/Main/Base/Project/Dom/IAssemblyModel.cs index 4f496c33d4..11a081dd01 100644 --- a/src/Main/Base/Project/Dom/IAssemblyModel.cs +++ b/src/Main/Base/Project/Dom/IAssemblyModel.cs @@ -2,6 +2,7 @@ // This code is distributed under the GNU LGPL (for details please see \doc\license.txt) using System; +using System.Collections.Generic; using System.Linq; using ICSharpCode.NRefactory.TypeSystem; @@ -57,6 +58,11 @@ namespace ICSharpCode.SharpDevelop.Dom /// void Update(IUnresolvedFile oldFile, IUnresolvedFile newFile); + /// + /// Updates the parse information with the given list of top-level type definitions. + /// + void Update(IList oldFile, IList newFile); + /// /// Gets the assembly name (short name). /// diff --git a/src/Main/Base/Project/Dom/ITypeDefinitionModelCollection.cs b/src/Main/Base/Project/Dom/ITypeDefinitionModelCollection.cs index 47a62b2a56..bcb51faeea 100644 --- a/src/Main/Base/Project/Dom/ITypeDefinitionModelCollection.cs +++ b/src/Main/Base/Project/Dom/ITypeDefinitionModelCollection.cs @@ -31,7 +31,7 @@ namespace ICSharpCode.SharpDevelop.Dom /// /// Updates the collection when the parse information has changed. /// - void Update(IUnresolvedFile oldFile, IUnresolvedFile newFile); + void Update(IList oldFile, IList newFile); } public sealed class EmptyTypeDefinitionModelCollection : ITypeDefinitionModelCollection @@ -70,7 +70,7 @@ namespace ICSharpCode.SharpDevelop.Dom return Enumerable.Empty().GetEnumerator(); } - void ITypeDefinitionModelCollection.Update(IUnresolvedFile oldFile, IUnresolvedFile newFile) + void ITypeDefinitionModelCollection.Update(IList oldFile, IList newFile) { throw new NotSupportedException(); } diff --git a/src/Main/SharpDevelop/Dom/AssemblyModel.cs b/src/Main/SharpDevelop/Dom/AssemblyModel.cs index accac7f252..1cecb2ee50 100644 --- a/src/Main/SharpDevelop/Dom/AssemblyModel.cs +++ b/src/Main/SharpDevelop/Dom/AssemblyModel.cs @@ -5,6 +5,7 @@ using System; using System.Collections.Generic; using System.ComponentModel; using System.Linq; +using ICSharpCode.NRefactory; using ICSharpCode.NRefactory.TypeSystem; using ICSharpCode.SharpDevelop.Parser; using ICSharpCode.SharpDevelop.Project; @@ -50,6 +51,18 @@ namespace ICSharpCode.SharpDevelop.Dom } public void Update(IUnresolvedFile oldFile, IUnresolvedFile newFile) + { + IList old = EmptyList.Instance; + IList @new = EmptyList.Instance; + if (oldFile != null) + old = oldFile.TopLevelTypeDefinitions; + if (newFile != null) + @new = newFile.TopLevelTypeDefinitions; + + typeDeclarations.Update(old, @new); + } + + public void Update(IList oldFile, IList newFile) { typeDeclarations.Update(oldFile, newFile); } diff --git a/src/Main/SharpDevelop/Dom/TopLevelTypeDefinitionModelCollection.cs b/src/Main/SharpDevelop/Dom/TopLevelTypeDefinitionModelCollection.cs index 5b65d65f82..7d619539af 100644 --- a/src/Main/SharpDevelop/Dom/TopLevelTypeDefinitionModelCollection.cs +++ b/src/Main/SharpDevelop/Dom/TopLevelTypeDefinitionModelCollection.cs @@ -72,49 +72,45 @@ namespace ICSharpCode.SharpDevelop.Dom /// /// Updates the parse information. /// - public void Update(IUnresolvedFile oldFile, IUnresolvedFile newFile) + public void Update(IList oldFile, IList newFile) { List oldModels = null; List newModels = null; bool[] oldTypeDefHandled = null; - if (oldFile != null) { - oldTypeDefHandled = new bool[oldFile.TopLevelTypeDefinitions.Count]; + if (oldFile.Count > 0) { + oldTypeDefHandled = new bool[oldFile.Count]; } - if (newFile != null) { - foreach (var newPart in newFile.TopLevelTypeDefinitions) { - FullTypeName newFullTypeName = newPart.FullTypeName; - TypeDefinitionModel model; - if (dict.TryGetValue(newFullTypeName.TopLevelTypeName, out model)) { - // Existing type changed - // Find a matching old part: - IUnresolvedTypeDefinition oldPart = null; - if (oldFile != null) { - for (int i = 0; i < oldTypeDefHandled.Length; i++) { - if (oldTypeDefHandled[i]) - continue; - if (oldFile.TopLevelTypeDefinitions[i].FullTypeName == newFullTypeName) { - oldTypeDefHandled[i] = true; - oldPart = oldFile.TopLevelTypeDefinitions[i]; - break; - } - } + foreach (var newPart in newFile) { + FullTypeName newFullTypeName = newPart.FullTypeName; + TypeDefinitionModel model; + if (dict.TryGetValue(newFullTypeName.TopLevelTypeName, out model)) { + // Existing type changed + // Find a matching old part: + IUnresolvedTypeDefinition oldPart = null; + for (int i = 0; i < oldTypeDefHandled.Length; i++) { + if (oldTypeDefHandled[i]) + continue; + if (oldFile[i].FullTypeName == newFullTypeName) { + oldTypeDefHandled[i] = true; + oldPart = oldFile[i]; + break; } - model.Update(oldPart, newPart); - } else { - // New type added - model = new TypeDefinitionModel(context, newPart); - dict.Add(newFullTypeName.TopLevelTypeName, model); - if (newModels == null) - newModels = new List(); - newModels.Add(model); } + model.Update(oldPart, newPart); + } else { + // New type added + model = new TypeDefinitionModel(context, newPart); + dict.Add(newFullTypeName.TopLevelTypeName, model); + if (newModels == null) + newModels = new List(); + newModels.Add(model); } } // Remove all old parts that weren't updated: - if (oldFile != null) { + if (oldTypeDefHandled != null) { for (int i = 0; i < oldTypeDefHandled.Length; i++) { if (!oldTypeDefHandled[i]) { - IUnresolvedTypeDefinition oldPart = oldFile.TopLevelTypeDefinitions[i]; + IUnresolvedTypeDefinition oldPart = oldFile[i]; TopLevelTypeName topLevelTypeName = oldPart.FullTypeName.TopLevelTypeName; TypeDefinitionModel model; if (dict.TryGetValue(topLevelTypeName, out model)) {