Browse Source

add simple implementation of ClassBrowserPad, ClassBrowserTreeView and some tree nodes

addin-manager-package-subdirectories
Siegfried Pammer 12 years ago
parent
commit
035cbe30b7
  1. 52
      src/AddIns/Analysis/UnitTesting/Pad/UnitTestNode.cs
  2. 42
      src/Main/Base/Project/Dom/ClassBrowser/ClassBrowserTreeView.cs
  3. 84
      src/Main/Base/Project/Dom/ClassBrowser/ClassBrowserWorkspace.cs
  4. 186
      src/Main/Base/Project/Dom/ClassBrowser/WorkspaceTreeNode.cs
  5. 50
      src/Main/Base/Project/Dom/IAssemblyModel.cs
  6. 6
      src/Main/Base/Project/Dom/IModelFactory.cs
  7. 44
      src/Main/Base/Project/Dom/INamespaceModel.cs
  8. 47
      src/Main/Base/Project/Dom/KeyedModelCollection.cs
  9. 116
      src/Main/Base/Project/Dom/ModelCollectionTreeNode.cs
  10. 8
      src/Main/Base/Project/ICSharpCode.SharpDevelop.addin
  11. 7
      src/Main/Base/Project/ICSharpCode.SharpDevelop.csproj
  12. 4
      src/Main/Base/Project/Src/Project/AbstractProject.cs
  13. 18
      src/Main/Base/Project/Src/Project/CompilableProject.cs
  14. 5
      src/Main/Base/Project/Src/Project/IProject.cs
  15. 16
      src/Main/Base/Project/Src/Services/IconService.cs
  16. 4
      src/Main/Base/Project/Util/SharpDevelopExtensions.cs
  17. 88
      src/Main/SharpDevelop/Dom/ClassBrowser/ClassBrowserPad.cs
  18. 43
      src/Main/SharpDevelop/Dom/ClassBrowser/WorkspaceTreeNodesFactory.cs
  19. 4
      src/Main/SharpDevelop/Dom/ModelFactory.cs
  20. 77
      src/Main/SharpDevelop/Dom/NamespaceModel.cs
  21. 98
      src/Main/SharpDevelop/Dom/ProjectAssemblyModel.cs
  22. 5
      src/Main/SharpDevelop/SharpDevelop.csproj

52
src/AddIns/Analysis/UnitTesting/Pad/UnitTestNode.cs

@ -8,11 +8,12 @@ using System.Linq; @@ -8,11 +8,12 @@ using System.Linq;
using System.Windows;
using ICSharpCode.NRefactory.Utils;
using ICSharpCode.SharpDevelop;
using ICSharpCode.SharpDevelop.Dom;
using ICSharpCode.TreeView;
namespace ICSharpCode.UnitTesting
{
public class UnitTestNode : SharpTreeNode
public class UnitTestNode : ModelCollectionTreeNode
{
protected static readonly IComparer<SharpTreeNode> NodeTextComparer = KeyComparer.Create((SharpTreeNode n) => n.Text.ToString(), StringComparer.OrdinalIgnoreCase, StringComparer.OrdinalIgnoreCase);
@ -28,21 +29,27 @@ namespace ICSharpCode.UnitTesting @@ -28,21 +29,27 @@ namespace ICSharpCode.UnitTesting
LazyLoading = true;
}
void DetachEventHandlers()
protected override void DetachEventHandlers()
{
// TODO: figure out when we can call this method
test.DisplayNameChanged -= test_NameChanged;
test.ResultChanged -= test_ResultChanged;
// If children loaded, also detach the collection change event handler
if (!LazyLoading) {
test.NestedTests.CollectionChanged -= test_NestedTests_CollectionChanged;
}
base.DetachEventHandlers();
}
public new ITest Model {
get { return test; }
}
protected override IModelCollection<object> ModelChildren {
get { return test.NestedTests; }
}
protected override IComparer<SharpTreeNode> NodeComparer {
get { return NodeTextComparer; }
}
protected override object GetModel()
{
return test;
@ -58,39 +65,6 @@ namespace ICSharpCode.UnitTesting @@ -58,39 +65,6 @@ namespace ICSharpCode.UnitTesting
public override bool ShowExpander {
get { return test.CanExpandNestedTests && base.ShowExpander; }
}
protected override void LoadChildren()
{
Children.Clear();
InsertNestedTests(test.NestedTests);
test.NestedTests.CollectionChanged += test_NestedTests_CollectionChanged;
}
void InsertNestedTests(IEnumerable<ITest> nestedTests)
{
foreach (var nestedTest in nestedTests) {
var treeNode = SD.TreeNodeFactory.CreateTreeNode(nestedTest);
if (treeNode != null)
Children.OrderedInsert(treeNode, NodeTextComparer);
}
}
void test_NestedTests_CollectionChanged(IReadOnlyCollection<ITest> removedItems, IReadOnlyCollection<ITest> addedItems)
{
if (!IsVisible) {
SwitchBackToLazyLoading();
return;
}
Children.RemoveAll(n => removedItems.Contains(n.Model));
InsertNestedTests(addedItems);
}
void SwitchBackToLazyLoading()
{
test.NestedTests.CollectionChanged -= test_NestedTests_CollectionChanged;
Children.Clear();
LazyLoading = true;
}
#endregion
#region Icon + Text

42
src/Main/Base/Project/Dom/ClassBrowser/ClassBrowserTreeView.cs

@ -0,0 +1,42 @@ @@ -0,0 +1,42 @@
// 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.Diagnostics;
using System.Windows.Controls;
using ICSharpCode.Core.Presentation;
using ICSharpCode.TreeView;
using ICSharpCode.SharpDevelop.Workbench;
namespace ICSharpCode.SharpDevelop.Dom.ClassBrowser
{
public class ClassBrowserTreeView : SharpTreeView, IClassBrowserTreeView
{
ClassBrowserWorkspace currentWorkspace;
public ClassBrowserTreeView()
{
Workspace = ClassBrowserSettings.LoadDefaultWorkspace();
}
public ClassBrowserWorkspace Workspace {
get { return currentWorkspace; }
set {
if (currentWorkspace == value)
return;
currentWorkspace = value;
if (currentWorkspace != null) {
this.Root = new WorkspaceTreeNode(currentWorkspace);
this.ShowRoot = currentWorkspace.LoadedAssemblies.Count > 0 || !currentWorkspace.IsAssigned;
} else {
this.Root = null;
}
}
}
}
public interface IClassBrowserTreeView
{
}
}

84
src/Main/Base/Project/Dom/ClassBrowser/ClassBrowserWorkspace.cs

@ -0,0 +1,84 @@ @@ -0,0 +1,84 @@
// 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.Collections.Generic;
using System.Linq;
using ICSharpCode.Core;
using ICSharpCode.NRefactory;
using ICSharpCode.NRefactory.TypeSystem;
using ICSharpCode.NRefactory.TypeSystem.Implementation;
using ICSharpCode.SharpDevelop.Project;
namespace ICSharpCode.SharpDevelop.Dom.ClassBrowser
{
/// <summary>
/// Description of ClassBrowserWorkspace.
/// </summary>
public class ClassBrowserWorkspace
{
ISolution assignedSolution;
IModelCollection<IUnresolvedAssembly> loadedAssemblies;
string workspaceName;
public ClassBrowserWorkspace(ISolution assignedSolution, IEnumerable<IUnresolvedAssembly> assemblies = null)
: this(assignedSolution.FileName, assemblies)
{
this.assignedSolution = assignedSolution;
}
public ClassBrowserWorkspace(string workspaceName, IEnumerable<IUnresolvedAssembly> assemblies = null)
{
this.workspaceName = workspaceName;
this.loadedAssemblies = new SimpleModelCollection<IUnresolvedAssembly>(assemblies ?? EmptyList<IUnresolvedAssembly>.Instance);
}
public bool IsAssigned {
get { return assignedSolution != null; }
}
public ISolution AssignedSolution {
get { return assignedSolution; }
}
public string Name {
get { return workspaceName; }
}
public IModelCollection<IUnresolvedAssembly> LoadedAssemblies {
get { return loadedAssemblies; }
}
}
public static class ClassBrowserSettings
{
static IUnresolvedAssembly[] LoadAssemblyList(string name)
{
var assemblyNames = Container.GetList<string>("AssemblyList." + name);
CecilLoader loader = new CecilLoader();
return assemblyNames.Select(loader.LoadAssemblyFile).ToArray();
}
static readonly Properties Container = SD.PropertyService.NestedProperties(typeof(ClassBrowserSettings).FullName);
public static ClassBrowserWorkspace LoadDefaultWorkspace()
{
return LoadWorkspace("<default>");
}
public static ClassBrowserWorkspace LoadWorkspace(string name)
{
return new ClassBrowserWorkspace(name, LoadAssemblyList(name));
}
public static ClassBrowserWorkspace LoadForSolution(ISolution solution)
{
return new ClassBrowserWorkspace(solution, LoadAssemblyList(solution.FileName));
}
public static void SaveWorkspace(ClassBrowserWorkspace workspace)
{
}
}
}

186
src/Main/Base/Project/Dom/ClassBrowser/WorkspaceTreeNode.cs

@ -0,0 +1,186 @@ @@ -0,0 +1,186 @@
// 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.Collections.Generic;
using System.Windows.Media;
using ICSharpCode.NRefactory.Utils;
using ICSharpCode.TreeView;
using ICSharpCode.SharpDevelop.Project;
namespace ICSharpCode.SharpDevelop.Dom.ClassBrowser
{
/// <summary>
/// Description of WorkspaceTreeNode.
/// </summary>
public class WorkspaceTreeNode : ModelCollectionTreeNode
{
ClassBrowserWorkspace workspace;
public WorkspaceTreeNode(ClassBrowserWorkspace workspace)
{
if (workspace == null)
throw new ArgumentNullException("workspace");
this.workspace = workspace;
}
protected override IModelCollection<object> ModelChildren {
get { return workspace.LoadedAssemblies; }
}
protected override IComparer<SharpTreeNode> NodeComparer {
get { return NodeTextComparer; }
}
public override object Text {
get {
return "Workspace " + workspace.Name;
}
}
protected override bool IsSpecialNode()
{
return true;
}
protected override void InsertSpecialNodes()
{
if (workspace.IsAssigned) {
InsertChildren(new[] { workspace.AssignedSolution });
}
}
}
public class SolutionTreeNode : ModelCollectionTreeNode
{
ISolution solution;
public SolutionTreeNode(ISolution solution)
{
if (solution == null)
throw new ArgumentNullException("solution");
this.solution = solution;
}
public override object Text {
get { return "Solution " + solution.Name; }
}
public override object Icon {
get { return IconService.GetImageSource("Icons.16x16.SolutionIcon"); }
}
protected override IComparer<SharpTreeNode> NodeComparer {
get { return NodeTextComparer; }
}
protected override IModelCollection<object> ModelChildren {
get { return solution.Projects; }
}
}
public class ProjectTreeNode : ModelCollectionTreeNode
{
IProject project;
public ProjectTreeNode(IProject project)
{
if (project == null)
throw new ArgumentNullException("project");
this.project = project;
}
public override object Text {
get { return project.Name; }
}
public override object Icon {
get { return IconService.GetImageSource(IconService.GetImageForProjectType(project.Language)); }
}
protected override IComparer<SharpTreeNode> NodeComparer {
get { return NodeTextComparer; }
}
protected override IModelCollection<object> ModelChildren {
get { return project.AssemblyModel.Namespaces; }
}
}
public class AssemblyTreeNode : ModelCollectionTreeNode
{
IAssemblyModel model;
public AssemblyTreeNode(IAssemblyModel model)
{
if (model == null)
throw new ArgumentNullException("model");
this.model = model;
}
protected override IComparer<SharpTreeNode> NodeComparer {
get { return NodeTextComparer; }
}
protected override IModelCollection<object> ModelChildren {
get { return model.Namespaces; }
}
}
public class NamespaceTreeNode : ModelCollectionTreeNode
{
INamespaceModel model;
public NamespaceTreeNode(INamespaceModel model)
{
if (model == null)
throw new ArgumentNullException("model");
this.model = model;
}
protected override IComparer<SharpTreeNode> NodeComparer {
get { return NodeTextComparer; }
}
protected override IModelCollection<object> ModelChildren {
get { return model.Types; }
}
public override object Icon {
get { return ClassBrowserIconService.Namespace.ImageSource; }
}
public override object Text {
get { return model.FullName; }
}
}
public class TypeDefinitionTreeNode : ModelCollectionTreeNode
{
ITypeDefinitionModel definition;
public TypeDefinitionTreeNode(ITypeDefinitionModel definition)
{
if (definition == null)
throw new ArgumentNullException("definition");
this.definition = definition;
}
public override object Icon {
// TODO why do I have to resolve this?
get { return ClassBrowserIconService.GetIcon(definition.Resolve()).ImageSource; }
}
public override object Text {
get { return definition.Name; }
}
protected override IComparer<SharpTreeNode> NodeComparer {
get { return NodeTextComparer; }
}
protected override IModelCollection<object> ModelChildren {
get { return definition.Members; }
}
}
}

50
src/Main/Base/Project/Dom/IAssemblyModel.cs

@ -0,0 +1,50 @@ @@ -0,0 +1,50 @@
// 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.Linq;
using ICSharpCode.NRefactory.TypeSystem;
namespace ICSharpCode.SharpDevelop.Dom
{
public interface IAssemblyModel
{
string Name { get; }
ITypeDefinitionModelCollection TopLevelTypeDefinitions { get; }
IModelCollection<INamespaceModel> Namespaces { get; }
INamespaceModel RootNamespace { get; }
}
public interface IUpdateableAssemblyModel : IAssemblyModel
{
void Update(IUnresolvedFile oldFile, IUnresolvedFile newFile);
}
public sealed class EmptyAssemblyModel : IAssemblyModel
{
public readonly static IAssemblyModel Instance = new EmptyAssemblyModel();
EmptyAssemblyModel()
{
}
public string Name {
get { return string.Empty; }
}
public ITypeDefinitionModelCollection TopLevelTypeDefinitions {
get { return EmptyTypeDefinitionModelCollection.Instance; }
}
public IModelCollection<INamespaceModel> Namespaces {
get { return ImmutableModelCollection<INamespaceModel>.Empty; }
}
public INamespaceModel RootNamespace {
get { return EmptyNamespaceModel.Instance; }
}
}
}

6
src/Main/Base/Project/Dom/IModelFactory.cs

@ -13,12 +13,8 @@ namespace ICSharpCode.SharpDevelop.Dom @@ -13,12 +13,8 @@ namespace ICSharpCode.SharpDevelop.Dom
[SDService]
public interface IModelFactory
{
/// <summary>
/// Creates an empty type definition collection that holds the top-level types for a project.
/// </summary>
ITypeDefinitionModelCollection CreateTopLevelTypeDefinitionCollection(IEntityModelContext context);
ITypeDefinitionModel CreateTypeDefinitionModel(IEntityModelContext context, params IUnresolvedTypeDefinition[] parts);
IMemberModel CreateMemberModel(IEntityModelContext context, IUnresolvedMember member);
IAssemblyModel CreateAssemblyModel(IEntityModelContext context);
}
}

44
src/Main/Base/Project/Dom/INamespaceModel.cs

@ -2,6 +2,7 @@ @@ -2,6 +2,7 @@
// This code is distributed under the GNU LGPL (for details please see \doc\license.txt)
using System;
using ICSharpCode.NRefactory.TypeSystem;
namespace ICSharpCode.SharpDevelop.Dom
{
@ -16,4 +17,47 @@ namespace ICSharpCode.SharpDevelop.Dom @@ -16,4 +17,47 @@ namespace ICSharpCode.SharpDevelop.Dom
IModelCollection<INamespaceModel> ChildNamespaces { get; }
IModelCollection<ITypeDefinitionModel> Types { get; }
}
public sealed class EmptyNamespaceModel : INamespaceModel
{
public readonly static INamespaceModel Instance = new EmptyNamespaceModel();
EmptyNamespaceModel()
{
}
public event System.ComponentModel.PropertyChangedEventHandler PropertyChanged;
public string FullName {
get { return string.Empty; }
}
public INamespaceModel ParentNamespace {
get { return null; }
}
public IModelCollection<INamespaceModel> ChildNamespaces {
get { return ImmutableModelCollection<INamespaceModel>.Empty; }
}
public IModelCollection<ITypeDefinitionModel> Types {
get { return EmptyTypeDefinitionModelCollection.Instance; }
}
public string Name {
get { return string.Empty; }
}
public SymbolKind SymbolKind {
get { return SymbolKind.Namespace; }
}
public ICSharpCode.SharpDevelop.Project.IProject ParentProject {
get { return null; }
}
public DomRegion Region {
get { return DomRegion.Empty; }
}
}
}

47
src/Main/Base/Project/Dom/KeyedModelCollection.cs

@ -0,0 +1,47 @@ @@ -0,0 +1,47 @@
// 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;
using System.Collections.Generic;
using System.Linq;
namespace ICSharpCode.SharpDevelop.Dom
{
public class KeyedModelCollection<TKey, TValue> : SimpleModelCollection<TValue>
{
Func<TValue, TKey> getKeyForValue;
Dictionary<TKey, TValue> dict;
public KeyedModelCollection(Func<TValue, TKey> getKeyForValue, IEqualityComparer<TKey> comparer = null)
{
if (getKeyForValue == null)
throw new ArgumentNullException("getKeyForValue");
this.getKeyForValue = getKeyForValue;
this.dict = new Dictionary<TKey, TValue>(comparer ?? EqualityComparer<TKey>.Default);
}
protected override void OnAdd(TValue item)
{
base.OnAdd(item);
dict.Add(getKeyForValue(item), item);
}
protected override void OnRemove(TValue item)
{
base.OnRemove(item);
dict.Remove(getKeyForValue(item));
}
public TValue this[TKey key] {
get { return dict[key]; }
}
public bool TryGetValue(TKey key, out TValue value)
{
return dict.TryGetValue(key, out value);
}
}
}

116
src/Main/Base/Project/Dom/ModelCollectionTreeNode.cs

@ -0,0 +1,116 @@ @@ -0,0 +1,116 @@
// 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.Collections;
using System.Collections.Generic;
using System.Linq;
using ICSharpCode.NRefactory.Utils;
using ICSharpCode.TreeView;
namespace ICSharpCode.SharpDevelop.Dom
{
public abstract class ModelCollectionTreeNode : SharpTreeNode
{
protected static readonly IComparer<SharpTreeNode> NodeTextComparer = KeyComparer.Create((SharpTreeNode n) => n.Text.ToString(), StringComparer.OrdinalIgnoreCase, StringComparer.OrdinalIgnoreCase);
protected ModelCollectionTreeNode()
{
this.LazyLoading = true;
}
protected abstract IModelCollection<object> ModelChildren { get; }
protected abstract IComparer<SharpTreeNode> NodeComparer { get; }
protected virtual bool IsSpecialNode()
{
return false;
}
protected virtual void InsertSpecialNodes()
{
throw new NotSupportedException("this node is not a special node!");
}
protected virtual void DetachEventHandlers()
{
// If children loaded, also detach the collection change event handler
if (!LazyLoading) {
ModelChildren.CollectionChanged -= ModelChildrenCollectionChanged;
}
}
protected override void OnIsVisibleChanged()
{
base.OnIsVisibleChanged();
if (IsVisible) {
if (!LazyLoading) {
ModelChildren.CollectionChanged += ModelChildrenCollectionChanged;
SynchronizeModelChildren();
}
} else {
ModelChildren.CollectionChanged -= ModelChildrenCollectionChanged;
}
}
#region Manage Children
protected override void LoadChildren()
{
Children.Clear();
if (IsSpecialNode())
InsertSpecialNodes();
InsertChildren(ModelChildren);
ModelChildren.CollectionChanged += ModelChildrenCollectionChanged;
}
protected void InsertChildren(IEnumerable children)
{
foreach (object child in children) {
var treeNode = SD.TreeNodeFactory.CreateTreeNode(child);
if (treeNode != null)
Children.OrderedInsert(treeNode, NodeComparer);
}
}
void SynchronizeModelChildren()
{
HashSet<object> set = new HashSet<object>(ModelChildren);
Children.RemoveAll(n => !set.Contains(n.Model));
set.ExceptWith(Children.Select(n => n.Model));
InsertChildren(set);
}
void ModelChildrenCollectionChanged(IReadOnlyCollection<object> removedItems, IReadOnlyCollection<object> addedItems)
{
if (!IsVisible) {
SwitchBackToLazyLoading();
return;
}
Children.RemoveAll(n => removedItems.Contains(n.Model));
InsertChildren(addedItems);
}
void SwitchBackToLazyLoading()
{
ModelChildren.CollectionChanged -= ModelChildrenCollectionChanged;
Children.Clear();
LazyLoading = true;
}
#endregion
}
public class WaitForSolutionLoadedTreeNode : SharpTreeNode
{
public WaitForSolutionLoadedTreeNode()
{
this.LazyLoading = false;
}
public override object Text {
get {
return "Waiting for solution load to be completed...";
}
}
}
}

8
src/Main/Base/Project/ICSharpCode.SharpDevelop.addin

@ -129,14 +129,12 @@ @@ -129,14 +129,12 @@
class = "ICSharpCode.SharpDevelop.Project.ProjectBrowserPad"
defaultPosition = "Left" />
<!--
<Pad id = "ClassBrowser"
category = "Main"
title = "${res:MainWindow.Windows.ClassScoutLabel}"
icon = "PadIcons.ClassBrowser"
class = "ICSharpCode.SharpDevelop.Gui.ClassBrowser.ClassBrowserPad"
class = "ICSharpCode.SharpDevelop.Dom.ClassBrowser.ClassBrowserPad"
defaultPosition = "Right" />
-->
<Pad id = "SideBar"
category = "Main"
@ -2276,6 +2274,10 @@ @@ -2276,6 +2274,10 @@
class = "ICSharpCode.SharpDevelop.Gui.ClassBrowser.DefaultProjectNodeBuilder"/>
</Path>
<Path name="/SharpDevelop/TreeNodeFactories">
<Class id="WorkspaceTreeNodesFactory" class="ICSharpCode.SharpDevelop.Dom.ClassBrowser.WorkspaceTreeNodesFactory" />
</Path>
<Path name = "/SharpDevelop/Views/ClassBrowser/ClassNodeBuilders">
<Class id = "DefaultClassBuilder"
class = "ICSharpCode.SharpDevelop.Gui.ClassBrowser.DefaultClassNodeBuilder"/>

7
src/Main/Base/Project/ICSharpCode.SharpDevelop.csproj

@ -84,6 +84,10 @@ @@ -84,6 +84,10 @@
</Compile>
<Compile Include="Designer\IDesignerTypeResolutionService.cs" />
<Compile Include="Designer\TypeResolutionService.cs" />
<Compile Include="Dom\ClassBrowser\ClassBrowserTreeView.cs" />
<Compile Include="Dom\ClassBrowser\ClassBrowserWorkspace.cs" />
<Compile Include="Dom\ClassBrowser\WorkspaceTreeNode.cs" />
<Compile Include="Dom\IAssemblyModel.cs" />
<Compile Include="Dom\IEntityModelContext.cs" />
<Compile Include="Dom\IEventModel.cs" />
<Compile Include="Dom\IFieldModel.cs" />
@ -98,8 +102,10 @@ @@ -98,8 +102,10 @@
<Compile Include="Dom\IEntityModel.cs" />
<Compile Include="Dom\IModelCollection.cs" />
<Compile Include="Dom\ITreeNodeFactory.cs" />
<Compile Include="Dom\KeyedModelCollection.cs" />
<Compile Include="Dom\ModelCollectionLinq.cs" />
<Compile Include="Dom\ImmutableModelCollection.cs" />
<Compile Include="Dom\ModelCollectionTreeNode.cs" />
<Compile Include="Dom\SimpleModelCollection.cs" />
<Compile Include="Dom\SynchronizedModelCollection.cs" />
<Compile Include="Editor\AvalonEditTextEditorAdapter.cs" />
@ -811,6 +817,7 @@ @@ -811,6 +817,7 @@
</ItemGroup>
<ItemGroup>
<Folder Include="Designer" />
<Folder Include="Dom\ClassBrowser" />
<Folder Include="Src\Editor\Dialogs" />
<Folder Include="Templates" />
<Folder Include="Project\Configuration" />

4
src/Main/Base/Project/Src/Project/AbstractProject.cs

@ -691,9 +691,9 @@ namespace ICSharpCode.SharpDevelop.Project @@ -691,9 +691,9 @@ namespace ICSharpCode.SharpDevelop.Project
}
[Browsable(false)]
public virtual ICSharpCode.SharpDevelop.Dom.ITypeDefinitionModelCollection TypeDefinitionModels {
public virtual IAssemblyModel AssemblyModel {
get {
return EmptyTypeDefinitionModelCollection.Instance;
return EmptyAssemblyModel.Instance;
}
}

18
src/Main/Base/Project/Src/Project/CompilableProject.cs

@ -327,7 +327,7 @@ namespace ICSharpCode.SharpDevelop.Project @@ -327,7 +327,7 @@ namespace ICSharpCode.SharpDevelop.Project
#region Type System
volatile ProjectContentContainer projectContentContainer;
ITypeDefinitionModelCollection typeDefinitionModels;
IAssemblyModel assemblyModel;
protected void InitializeProjectContent(IProjectContent initialProjectContent)
{
@ -351,20 +351,20 @@ namespace ICSharpCode.SharpDevelop.Project @@ -351,20 +351,20 @@ namespace ICSharpCode.SharpDevelop.Project
}
}
public override ITypeDefinitionModelCollection TypeDefinitionModels {
public override IAssemblyModel AssemblyModel {
get {
SD.MainThread.VerifyAccess();
if (typeDefinitionModels == null) {
typeDefinitionModels = SD.GetRequiredService<IModelFactory>().CreateTopLevelTypeDefinitionCollection(new ProjectEntityModelContext(this, ".cs"));
if (assemblyModel == null) {
assemblyModel = SD.GetRequiredService<IModelFactory>().CreateAssemblyModel(new ProjectEntityModelContext(this, ".cs"));
var pc = ProjectContent;
if (pc != null) {
if (pc != null && assemblyModel is IUpdateableAssemblyModel) {
// Add the already loaded files into the model
foreach (var file in pc.Files) {
typeDefinitionModels.Update(null, file);
((IUpdateableAssemblyModel)assemblyModel).Update(null, file);
}
}
}
return typeDefinitionModels;
return assemblyModel;
}
}
@ -376,8 +376,8 @@ namespace ICSharpCode.SharpDevelop.Project @@ -376,8 +376,8 @@ namespace ICSharpCode.SharpDevelop.Project
// OnParseInformationUpdated is called inside a lock, but we don't want to raise the event inside that lock.
// To ensure events are raised in the same order, we always invoke on the main thread.
SD.MainThread.InvokeAsyncAndForget(delegate {
if (typeDefinitionModels != null) {
typeDefinitionModels.Update(args.OldUnresolvedFile, args.NewUnresolvedFile);
if (assemblyModel is IUpdateableAssemblyModel) {
((IUpdateableAssemblyModel)assemblyModel).Update(args.OldUnresolvedFile, args.NewUnresolvedFile);
}
ParseInformationUpdated(null, args);
});

5
src/Main/Base/Project/Src/Project/IProject.cs

@ -326,10 +326,9 @@ namespace ICSharpCode.SharpDevelop.Project @@ -326,10 +326,9 @@ namespace ICSharpCode.SharpDevelop.Project
void OnParseInformationUpdated(ParseInformationEventArgs args);
/// <summary>
/// Gets the models for the top-level type definitions in this project.
/// Never returns null, but may return a permanently empty collection if this project does not support such models.
/// Gets the assembly model for the project. This property never returns null.
/// </summary>
ITypeDefinitionModelCollection TypeDefinitionModels { get; }
IAssemblyModel AssemblyModel { get; }
/// <summary>
/// Gets whether this project was unloaded.

16
src/Main/Base/Project/Src/Services/IconService.cs

@ -74,6 +74,22 @@ namespace ICSharpCode.SharpDevelop @@ -74,6 +74,22 @@ namespace ICSharpCode.SharpDevelop
return SD.ResourceService.GetBitmap("Icons.16x16.MiscFiles");
}
public static System.Windows.Media.ImageSource GetImageSource(string name)
{
System.Windows.Media.ImageSource img;
try {
img = SD.ResourceService.GetImageSource(name);
} catch (ResourceNotFoundException ex) {
LoggingService.Warn(ex);
img = null;
}
if (img != null) {
return img;
}
return SD.ResourceService.GetImageSource("Icons.16x16.MiscFiles");
}
public static string GetImageForProjectType(string projectType)
{
if (projectFileHashtable.ContainsKey(projectType)) {

4
src/Main/Base/Project/Util/SharpDevelopExtensions.cs

@ -510,7 +510,7 @@ namespace ICSharpCode.SharpDevelop @@ -510,7 +510,7 @@ namespace ICSharpCode.SharpDevelop
IProject project = typeDefinition.ParentAssembly.GetProject();
if (project != null)
return project.TypeDefinitionModels[typeDefinition.FullTypeName];
return project.AssemblyModel.TopLevelTypeDefinitions[typeDefinition.FullTypeName];
else
return null;
}
@ -564,7 +564,7 @@ namespace ICSharpCode.SharpDevelop @@ -564,7 +564,7 @@ namespace ICSharpCode.SharpDevelop
IUnresolvedTypeDefinition unresolvedTypeDefinition = entity as IUnresolvedTypeDefinition ?? entity.DeclaringTypeDefinition;
if (unresolvedTypeDefinition == null)
return null;
ITypeDefinitionModel typeModel = project.TypeDefinitionModels[unresolvedTypeDefinition.FullTypeName];
ITypeDefinitionModel typeModel = project.AssemblyModel.TopLevelTypeDefinitions[unresolvedTypeDefinition.FullTypeName];
if (entity is IUnresolvedTypeDefinition || typeModel == null)
return typeModel;

88
src/Main/SharpDevelop/Dom/ClassBrowser/ClassBrowserPad.cs

@ -0,0 +1,88 @@ @@ -0,0 +1,88 @@
// 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.Diagnostics;
using System.Windows.Controls;
using ICSharpCode.Core.Presentation;
using ICSharpCode.TreeView;
using ICSharpCode.SharpDevelop.Project;
using ICSharpCode.SharpDevelop.Workbench;
namespace ICSharpCode.SharpDevelop.Dom.ClassBrowser
{
public class ClassBrowserPad : AbstractPadContent
{
IProjectService projectService;
ClassBrowserTreeView treeView;
DockPanel panel;
ToolBar toolBar;
public ClassBrowserPad()
: this(SD.GetRequiredService<IProjectService>())
{
}
public ClassBrowserPad(IProjectService projectService)
{
this.projectService = projectService;
panel = new DockPanel();
treeView = new ClassBrowserTreeView(); // treeView must be created first because it's used by CreateToolBar
toolBar = CreateToolBar("/SharpDevelop/Pads/ClassBrowser/Toolbar");
panel.Children.Add(toolBar);
DockPanel.SetDock(toolBar, Dock.Top);
panel.Children.Add(treeView);
//treeView.ContextMenu = CreateContextMenu("/SharpDevelop/Pads/UnitTestsPad/ContextMenu");
projectService.CurrentSolutionChanged += ProjectServiceCurrentSolutionChanged;
ProjectServiceCurrentSolutionChanged(null, null);
}
public override void Dispose()
{
projectService.CurrentSolutionChanged -= ProjectServiceCurrentSolutionChanged;
base.Dispose();
}
public override object Control {
get { return panel; }
}
public IClassBrowserTreeView TreeView {
get { return treeView; }
}
void ProjectServiceCurrentSolutionChanged(object sender, EventArgs e)
{
if (projectService.CurrentSolution == null) {
treeView.Workspace = ClassBrowserSettings.LoadDefaultWorkspace();
} else {
treeView.Workspace = ClassBrowserSettings.LoadForSolution(projectService.CurrentSolution);
}
}
/// <summary>
/// Virtual method so we can override this method and return
/// a dummy ToolBar when testing.
/// </summary>
protected virtual ToolBar CreateToolBar(string name)
{
Debug.Assert(treeView != null);
return ToolBarService.CreateToolBar(treeView, treeView, name);
}
/// <summary>
/// Virtual method so we can override this method and return
/// a dummy ContextMenu when testing.
/// </summary>
protected virtual ContextMenu CreateContextMenu(string name)
{
Debug.Assert(treeView != null);
return MenuService.CreateContextMenu(treeView, name);
}
}
}

43
src/Main/SharpDevelop/Dom/ClassBrowser/WorkspaceTreeNodesFactory.cs

@ -0,0 +1,43 @@ @@ -0,0 +1,43 @@
// 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.Collections.Generic;
using System.Windows.Media;
using ICSharpCode.NRefactory.Utils;
using ICSharpCode.TreeView;
using ICSharpCode.SharpDevelop.Project;
namespace ICSharpCode.SharpDevelop.Dom.ClassBrowser
{
public class WorkspaceTreeNodesFactory : ITreeNodeFactory
{
public Type GetSupportedType(object model)
{
if (model is ISolution)
return typeof(ISolution);
if (model is IProject)
return typeof(IProject);
if (model is INamespaceModel)
return typeof(INamespaceModel);
if (model is ITypeDefinitionModel)
return typeof(ITypeDefinitionModel);
return null;
}
public SharpTreeNode CreateTreeNode(object model)
{
if (model is ISolution)
return new SolutionTreeNode((ISolution)model);
if (model is IProject)
return new ProjectTreeNode((IProject)model);
if (model is INamespaceModel)
return new NamespaceTreeNode((INamespaceModel)model);
if (model is ITypeDefinitionModel)
return new TypeDefinitionTreeNode((ITypeDefinitionModel)model);
return null;
}
}
}

4
src/Main/SharpDevelop/Dom/ModelFactory.cs

@ -8,9 +8,9 @@ namespace ICSharpCode.SharpDevelop.Dom @@ -8,9 +8,9 @@ namespace ICSharpCode.SharpDevelop.Dom
{
sealed class ModelFactory : IModelFactory
{
public ITypeDefinitionModelCollection CreateTopLevelTypeDefinitionCollection(IEntityModelContext context)
public IAssemblyModel CreateAssemblyModel(IEntityModelContext context)
{
return new TopLevelTypeDefinitionModelCollection(context);
return new ProjectAssemblyModel(context);
}
public ITypeDefinitionModel CreateTypeDefinitionModel(IEntityModelContext context, params IUnresolvedTypeDefinition[] parts)

77
src/Main/SharpDevelop/Dom/NamespaceModel.cs

@ -0,0 +1,77 @@ @@ -0,0 +1,77 @@
// 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.Collections.Generic;
using System.ComponentModel;
using ICSharpCode.NRefactory.TypeSystem;
using ICSharpCode.SharpDevelop.Parser;
using ICSharpCode.SharpDevelop.Project;
namespace ICSharpCode.SharpDevelop.Dom
{
sealed class NamespaceModel : INamespaceModel
{
IEntityModelContext context;
string name;
NamespaceModel parent;
NullSafeSimpleModelCollection<NamespaceModel> childNamespaces;
NullSafeSimpleModelCollection<ITypeDefinitionModel> typeDefinitions;
public NamespaceModel(IEntityModelContext context, NamespaceModel parent, string name)
{
if (context == null)
throw new ArgumentNullException("context");
this.context = context;
this.parent = parent;
this.name = name;
this.typeDefinitions = new NullSafeSimpleModelCollection<ITypeDefinitionModel>();
this.childNamespaces = new NullSafeSimpleModelCollection<NamespaceModel>();
}
public event PropertyChangedEventHandler PropertyChanged;
public string FullName {
get {
if (parent == null || string.IsNullOrEmpty(parent.name))
return name;
return parent.name + "." + name;
}
}
public INamespaceModel ParentNamespace {
get { return parent; }
}
IModelCollection<INamespaceModel> INamespaceModel.ChildNamespaces {
get { return childNamespaces; }
}
IModelCollection<ITypeDefinitionModel> INamespaceModel.Types {
get { return typeDefinitions; }
}
public IMutableModelCollection<NamespaceModel> ChildNamespaces {
get { return childNamespaces; }
}
public IMutableModelCollection<ITypeDefinitionModel> Types {
get { return typeDefinitions; }
}
public string Name {
get { return name; }
}
public SymbolKind SymbolKind {
get { return SymbolKind.Namespace; }
}
public IProject ParentProject {
get { return context.Project; }
}
public DomRegion Region {
get { return DomRegion.Empty; }
}
}
}

98
src/Main/SharpDevelop/Dom/ProjectAssemblyModel.cs

@ -0,0 +1,98 @@ @@ -0,0 +1,98 @@
// 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.Collections.Generic;
using System.ComponentModel;
using System.Linq;
using ICSharpCode.NRefactory.TypeSystem;
using ICSharpCode.SharpDevelop.Parser;
using ICSharpCode.SharpDevelop.Project;
namespace ICSharpCode.SharpDevelop.Dom
{
sealed class ProjectAssemblyModel : IUpdateableAssemblyModel
{
IEntityModelContext context;
TopLevelTypeDefinitionModelCollection typeDeclarations;
KeyedModelCollection<string, NamespaceModel> namespaces;
NamespaceModel rootNamespace;
public ProjectAssemblyModel(IEntityModelContext context)
{
if (context == null)
throw new ArgumentNullException("context");
this.context = context;
this.rootNamespace = new NamespaceModel(context, null, "");
this.typeDeclarations = new TopLevelTypeDefinitionModelCollection(context);
this.typeDeclarations.CollectionChanged += TypeDeclarationsCollectionChanged;
this.namespaces = new KeyedModelCollection<string, NamespaceModel>(value => value.FullName);
}
public string Name {
get {
return context.Project.AssemblyName;
}
}
public ITypeDefinitionModelCollection TopLevelTypeDefinitions {
get {
return typeDeclarations;
}
}
public IModelCollection<INamespaceModel> Namespaces {
get {
return namespaces;
}
}
public INamespaceModel RootNamespace {
get {
return rootNamespace;
}
}
public void Update(IUnresolvedFile oldFile, IUnresolvedFile newFile)
{
typeDeclarations.Update(oldFile, newFile);
}
void TypeDeclarationsCollectionChanged(IReadOnlyCollection<ITypeDefinitionModel> removedItems, IReadOnlyCollection<ITypeDefinitionModel> addedItems)
{
NamespaceModel ns;
foreach (ITypeDefinitionModel removedItem in removedItems) {
if (namespaces.TryGetValue(removedItem.Namespace, out ns)) {
ns.Types.Remove(removedItem);
while (ns.ParentNamespace != null && ns.Types.Count == 0 && ns.ChildNamespaces.Count == 0) {
((NamespaceModel)ns.ParentNamespace).ChildNamespaces.Remove(ns);
namespaces.Remove(ns);
ns = (NamespaceModel)ns.ParentNamespace;
}
}
}
foreach (ITypeDefinitionModel addedItem in addedItems) {
if (!namespaces.TryGetValue(addedItem.Namespace, out ns)) {
string[] parts = addedItem.Namespace.Split('.');
int level = 0;
ns = rootNamespace;
while (level < parts.Length) {
var nextNS = ns.ChildNamespaces
.FirstOrDefault(n => n.Name == parts[level]);
if (nextNS == null) break;
ns = nextNS;
level++;
}
while (level < parts.Length) {
ns = new NamespaceModel(context, ns, parts[level]);
namespaces.Add(ns);
level++;
}
ns.Types.Add(addedItem);
}
}
}
}
}

5
src/Main/SharpDevelop/SharpDevelop.csproj

@ -106,9 +106,13 @@ @@ -106,9 +106,13 @@
<Compile Include="..\ICSharpCode.SharpDevelop.BuildWorker\ExtendedBinaryReader.cs">
<Link>Project\Build\MSBuildEngine\ExtendedBinaryReader.cs</Link>
</Compile>
<Compile Include="Dom\ClassBrowser\ClassBrowserPad.cs" />
<Compile Include="Dom\ClassBrowser\WorkspaceTreeNodesFactory.cs" />
<Compile Include="Dom\ModelFactory.cs" />
<Compile Include="Dom\MemberModel.cs" />
<Compile Include="Dom\NamespaceModel.cs" />
<Compile Include="Dom\NestedTypeDefinitionModelCollection.cs" />
<Compile Include="Dom\ProjectAssemblyModel.cs" />
<Compile Include="Dom\TopLevelTypeDefinitionModelCollection.cs" />
<Compile Include="Dom\TreeNodeFactoryService.cs" />
<Compile Include="Dom\TypeDefinitionModel.cs" />
@ -304,6 +308,7 @@ @@ -304,6 +308,7 @@
</ItemGroup>
<ItemGroup>
<Folder Include="Dom" />
<Folder Include="Dom\ClassBrowser" />
<Folder Include="Editor" />
<Folder Include="Editor\Bookmarks" />
<Folder Include="Templates" />

Loading…
Cancel
Save