Browse Source

implemented TreeViews of DependencyMatrix

pull/18/head
Siegfried Pammer 14 years ago
parent
commit
0ede6cfcb7
  1. 7
      SharpDevelop.sln
  2. 35
      src/AddIns/Analysis/CodeQuality/CodeQuality.csproj
  3. 72
      src/AddIns/Analysis/CodeQuality/Engine/AssemblyAnalyzer.cs
  4. 55
      src/AddIns/Analysis/CodeQuality/Engine/Dom/AssemblyNode.cs
  5. 44
      src/AddIns/Analysis/CodeQuality/Engine/Dom/EventNode.cs
  6. 44
      src/AddIns/Analysis/CodeQuality/Engine/Dom/FieldNode.cs
  7. 29
      src/AddIns/Analysis/CodeQuality/Engine/Dom/INode.cs
  8. 14
      src/AddIns/Analysis/CodeQuality/Engine/Dom/IValue.cs
  9. 44
      src/AddIns/Analysis/CodeQuality/Engine/Dom/MethodNode.cs
  10. 47
      src/AddIns/Analysis/CodeQuality/Engine/Dom/NamespaceNode.cs
  11. 44
      src/AddIns/Analysis/CodeQuality/Engine/Dom/PropertyNode.cs
  12. 60
      src/AddIns/Analysis/CodeQuality/Engine/Dom/Relationship.cs
  13. 46
      src/AddIns/Analysis/CodeQuality/Engine/Dom/TypeNode.cs
  14. 32
      src/AddIns/Analysis/CodeQuality/Gui/Controls/DependencyMatrix.cs
  15. 20
      src/AddIns/Analysis/CodeQuality/Gui/Controls/DependencyMatrixControl.cs
  16. 100
      src/AddIns/Analysis/CodeQuality/Gui/Controls/Matrix.cs
  17. 522
      src/AddIns/Analysis/CodeQuality/Gui/Controls/MatrixControl.cs
  18. 46
      src/AddIns/Analysis/CodeQuality/Gui/Controls/VisibleMatrix.cs
  19. 42
      src/AddIns/Analysis/CodeQuality/Gui/DependencyMatrixView.xaml
  20. 118
      src/AddIns/Analysis/CodeQuality/Gui/DependencyMatrixView.xaml.cs
  21. 9
      src/AddIns/Analysis/CodeQuality/Gui/MainView.xaml
  22. 21
      src/AddIns/Analysis/CodeQuality/Gui/MainView.xaml.cs
  23. 34
      src/AddIns/Analysis/CodeQuality/Gui/MatrixTreeNode.cs
  24. 195
      src/AddIns/Analysis/CodeQuality/Gui/NodeIconService.cs
  25. 71
      src/AddIns/Analysis/CodeQuality/Utils/DependencyColorizer.cs
  26. 140
      src/AddIns/Analysis/CodeQuality/Utils/DoubleKeyDictionary.cs
  27. 77
      src/AddIns/Analysis/CodeQuality/Utils/Extensions.cs
  28. 20
      src/AddIns/Analysis/CodeQuality/Utils/IColorizer.cs
  29. 17
      src/AddIns/Analysis/CodeQuality/Utils/Utils.cs
  30. 52
      src/Main/Base/Project/Src/Util/ScrollUtils.cs

7
SharpDevelop.sln

@ -505,6 +505,10 @@ Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "SourceAnalysis", "src\AddIn @@ -505,6 +505,10 @@ Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "SourceAnalysis", "src\AddIn
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "MachineSpecifications", "src\AddIns\Analysis\MachineSpecifications\MachineSpecifications\MachineSpecifications.csproj", "{D1DA3B8F-7313-4BDA-8880-461C5F007751}"
EndProject
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "CodeQuality", "CodeQuality", "{558479FB-A397-4EE9-A1AD-879F80D1FCD0}"
ProjectSection(SolutionItems) = postProject
EndProjectSection
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "CodeQuality", "src\AddIns\Analysis\CodeQuality\CodeQuality.csproj", "{3C532D80-32B4-40E5-B5FE-BC6BAE1A00E7}"
EndProject
Project("{00000000-0000-0000-0000-000000000000}") = "Tools", "src\Tools\Tools.build", "{3DF4060F-5EE0-41CF-8096-F27355FD5511}"
@ -1262,6 +1266,7 @@ Global @@ -1262,6 +1266,7 @@ Global
{08CE9972-283B-44F4-82FA-966F7DFA6B7A} = {F355E45F-F54F-4B42-8916-9A633A392789}
{CE498514-D12D-4B6E-AE0E-FEC29BD43748} = {F355E45F-F54F-4B42-8916-9A633A392789}
{D1DA3B8F-7313-4BDA-8880-461C5F007751} = {F355E45F-F54F-4B42-8916-9A633A392789}
{3C532D80-32B4-40E5-B5FE-BC6BAE1A00E7} = {F355E45F-F54F-4B42-8916-9A633A392789}
{558479FB-A397-4EE9-A1AD-879F80D1FCD0} = {F355E45F-F54F-4B42-8916-9A633A392789}
{3C532D80-32B4-40E5-B5FE-BC6BAE1A00E7} = {558479FB-A397-4EE9-A1AD-879F80D1FCD0}
EndGlobalSection
EndGlobal

35
src/AddIns/Analysis/CodeQuality/CodeQuality.csproj

@ -43,6 +43,7 @@ @@ -43,6 +43,7 @@
<Reference Include="System.Core">
<RequiredTargetFramework>3.5</RequiredTargetFramework>
</Reference>
<Reference Include="System.Drawing" />
<Reference Include="System.Xaml">
<RequiredTargetFramework>4.0</RequiredTargetFramework>
</Reference>
@ -53,16 +54,41 @@ @@ -53,16 +54,41 @@
<Reference Include="WindowsBase" />
</ItemGroup>
<ItemGroup>
<Compile Include="Engine\Dom\AssemblyNode.cs" />
<Compile Include="Engine\Dom\EventNode.cs" />
<Compile Include="Engine\Dom\FieldNode.cs" />
<Compile Include="Engine\Dom\INode.cs" />
<Compile Include="Engine\Dom\IValue.cs" />
<Compile Include="Engine\Dom\MethodNode.cs" />
<Compile Include="Engine\Dom\NamespaceNode.cs" />
<Compile Include="Engine\Dom\PropertyNode.cs" />
<Compile Include="Engine\Dom\Relationship.cs" />
<Compile Include="Engine\Dom\TypeNode.cs" />
<Compile Include="Engine\ILAnalyzer.cs" />
<Compile Include="Engine\AssemblyAnalyzer.cs" />
<Compile Include="Gui\AnalyzeCodeQualityViewContent.cs" />
<Compile Include="Gui\Commands\AnalyzeCodeQualityCommand.cs" />
<Compile Include="Gui\Controls\DependencyMatrix.cs" />
<Compile Include="Gui\Controls\DependencyMatrixControl.cs" />
<Compile Include="Gui\Controls\Matrix.cs" />
<Compile Include="Gui\Controls\MatrixControl.cs" />
<Compile Include="Gui\Controls\VisibleMatrix.cs" />
<Compile Include="Gui\DependencyMatrixView.xaml.cs">
<DependentUpon>DependencyMatrixView.xaml</DependentUpon>
<SubType>Code</SubType>
</Compile>
<Compile Include="Gui\MainView.xaml.cs">
<DependentUpon>MainView.xaml</DependentUpon>
<SubType>Code</SubType>
</Compile>
<Compile Include="Gui\MatrixTreeNode.cs" />
<Compile Include="Gui\NodeIconService.cs" />
<Compile Include="Properties\AssemblyInfo.cs" />
<Compile Include="Utils\DependencyColorizer.cs" />
<Compile Include="Utils\DoubleKeyDictionary.cs" />
<Compile Include="Utils\Extensions.cs" />
<Compile Include="Utils\IColorizer.cs" />
<Compile Include="Utils\Utils.cs" />
</ItemGroup>
<ItemGroup>
<None Include="CodeQuality.addin">
@ -73,7 +99,11 @@ @@ -73,7 +99,11 @@
<ProjectReference Include="..\..\..\Libraries\NewNRefactory\ICSharpCode.NRefactory\ICSharpCode.NRefactory.csproj">
<Project>{3B2A5653-EC97-4001-BB9B-D90F1AF2C371}</Project>
<Name>ICSharpCode.NRefactory</Name>
<Private>False</Private>
<Private>True</Private>
</ProjectReference>
<ProjectReference Include="..\..\..\Libraries\SharpTreeView\ICSharpCode.TreeView\ICSharpCode.TreeView.csproj">
<Project>{DDE2A481-8271-4EAC-A330-8FA6A38D13D1}</Project>
<Name>ICSharpCode.TreeView</Name>
</ProjectReference>
<ProjectReference Include="..\..\..\Main\Base\Project\ICSharpCode.SharpDevelop.csproj">
<Project>{2748AD25-9C63-4E12-877B-4DCE96FBED54}</Project>
@ -96,8 +126,11 @@ @@ -96,8 +126,11 @@
<Folder Include="Gui" />
<Folder Include="Engine" />
<Folder Include="Gui\Commands" />
<Folder Include="Gui\Controls" />
<Folder Include="Utils" />
</ItemGroup>
<ItemGroup>
<Page Include="Gui\DependencyMatrixView.xaml" />
<Page Include="Gui\MainView.xaml" />
</ItemGroup>
<Import Project="$(MSBuildBinPath)\Microsoft.CSharp.Targets" />

72
src/AddIns/Analysis/CodeQuality/Engine/AssemblyAnalyzer.cs

@ -17,25 +17,71 @@ namespace ICSharpCode.CodeQuality.Engine @@ -17,25 +17,71 @@ namespace ICSharpCode.CodeQuality.Engine
public class AssemblyAnalyzer
{
CecilLoader loader = new CecilLoader(true);
ICompilation compilation = null;
IUnresolvedAssembly mainAssem = null;
ICompilation compilation;
Dictionary<IAssembly, AssemblyNode> assemblyMappings;
Dictionary<string, NamespaceNode> namespaceMappings;
Dictionary<ITypeDefinition, TypeNode> typeMappings;
Dictionary<IMethod, MethodNode> methodMappings;
Dictionary<IField, FieldNode> fieldMappings;
List<string> fileNames;
public AssemblyAnalyzer(params string[] fileNames)
public AssemblyAnalyzer()
{
List<IUnresolvedAssembly> references = new List<IUnresolvedAssembly>();
foreach (string fileName in fileNames) {
if (mainAssem == null)
mainAssem = loader.LoadAssemblyFile(fileName);
else
references.Add(loader.LoadAssemblyFile(fileName));
}
compilation = new SimpleCompilation(mainAssem, references);
fileNames = new List<string>();
}
public void AddAssemblyFiles(params string[] files)
{
fileNames.AddRange(files);
}
public ReadOnlyCollection<AssemblyNode> Analyze()
{
AssemblyNode mainAssembly = new AssemblyNode();
return new ReadOnlyCollection<AssemblyNode>(new AssemblyNode[] { mainAssembly });
compilation = new SimpleCompilation(loader.LoadAssemblyFile(fileNames.First()), LoadOthorAssemblies());
assemblyMappings = new Dictionary<IAssembly, AssemblyNode>();
namespaceMappings = new Dictionary<string, NamespaceNode>();
AssemblyNode mainAssembly = new AssemblyNode(compilation.MainAssembly);
foreach (var type in compilation.GetAllTypeDefinitions()) {
AnalyzeType(type);
}
return new ReadOnlyCollection<AssemblyNode>(assemblyMappings.Values.ToList());
}
IEnumerable<IUnresolvedAssembly> LoadOthorAssemblies()
{
foreach (var file in fileNames.Skip(1)) {
yield return loader.LoadAssemblyFile(file);
}
}
NamespaceNode GetOrCreateNamespace(string namespaceName)
{
NamespaceNode result;
if (!namespaceMappings.TryGetValue(namespaceName, out result)) {
result = new NamespaceNode(namespaceName);
namespaceMappings.Add(namespaceName, result);
}
return result;
}
AssemblyNode GetOrCreateAssembly(IAssembly asm)
{
AssemblyNode result;
if (!assemblyMappings.TryGetValue(asm, out result)) {
result = new AssemblyNode(asm);
assemblyMappings.Add(asm, result);
}
return result;
}
void AnalyzeType(ITypeDefinition type)
{
var asm = GetOrCreateAssembly(type.ParentAssembly);
var ns = GetOrCreateNamespace(type.Namespace);
if (!asm.namespaces.Contains(ns))
asm.namespaces.Add(ns);
}
}
}

55
src/AddIns/Analysis/CodeQuality/Engine/Dom/AssemblyNode.cs

@ -0,0 +1,55 @@ @@ -0,0 +1,55 @@
// 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 ICSharpCode.NRefactory.TypeSystem;
namespace ICSharpCode.CodeQuality.Engine.Dom
{
public class AssemblyNode : INode
{
public AssemblyNode(IAssembly assembly)
{
this.AssemblyInfo = assembly;
namespaces = new List<INode>();
}
public IAssembly AssemblyInfo { get; private set; }
public string Name {
get { return AssemblyInfo.AssemblyName; }
}
internal List<INode> namespaces;
public IList<INode> Children {
get { return namespaces; }
}
public IEnumerable<INode> Uses {
get {
throw new NotImplementedException();
}
}
public IEnumerable<INode> UsedBy {
get {
throw new NotImplementedException();
}
}
public void CalculateMetricsAndFreeze(IEnumerable<AssemblyNode> assemblies)
{
}
public Relationship GetRelationship(INode value)
{
Relationship r = new Relationship();
if (value == this)
r.AddRelationship(RelationshipType.Same);
return r;
}
}
}

44
src/AddIns/Analysis/CodeQuality/Engine/Dom/EventNode.cs

@ -0,0 +1,44 @@ @@ -0,0 +1,44 @@
// 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 ICSharpCode.NRefactory.TypeSystem;
namespace ICSharpCode.CodeQuality.Engine.Dom
{
public class EventNode : INode
{
public string Name {
get {
throw new NotImplementedException();
}
}
public IList<INode> Children {
get {
throw new NotImplementedException();
}
}
public IEnumerable<INode> Uses {
get {
throw new NotImplementedException();
}
}
public IEnumerable<INode> UsedBy {
get {
throw new NotImplementedException();
}
}
public Relationship GetRelationship(INode value)
{
Relationship r = new Relationship();
if (value == this)
r.AddRelationship(RelationshipType.Same);
return r;
}
}
}

44
src/AddIns/Analysis/CodeQuality/Engine/Dom/FieldNode.cs

@ -0,0 +1,44 @@ @@ -0,0 +1,44 @@
// 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 ICSharpCode.NRefactory.TypeSystem;
namespace ICSharpCode.CodeQuality.Engine.Dom
{
public class FieldNode : INode
{
public string Name {
get {
throw new NotImplementedException();
}
}
public IList<INode> Children {
get {
throw new NotImplementedException();
}
}
public IEnumerable<INode> Uses {
get {
throw new NotImplementedException();
}
}
public IEnumerable<INode> UsedBy {
get {
throw new NotImplementedException();
}
}
public Relationship GetRelationship(INode value)
{
Relationship r = new Relationship();
if (value == this)
r.AddRelationship(RelationshipType.Same);
return r;
}
}
}

29
src/AddIns/Analysis/CodeQuality/Engine/Dom/INode.cs

@ -13,35 +13,10 @@ namespace ICSharpCode.CodeQuality.Engine.Dom @@ -13,35 +13,10 @@ namespace ICSharpCode.CodeQuality.Engine.Dom
public interface INode
{
string Name { get; }
IEnumerable<INode> Children { get; }
IList<INode> Children { get; }
IEnumerable<INode> Uses { get; }
IEnumerable<INode> UsedBy { get; }
}
public class AssemblyNode : INode
{
public IAssembly AssemblyInfo { get; private set; }
public string Name {
get { return AssemblyInfo.AssemblyName; }
}
public IEnumerable<INode> Children {
get {
throw new NotImplementedException();
}
}
public IEnumerable<INode> Uses {
get {
throw new NotImplementedException();
}
}
public IEnumerable<INode> UsedBy {
get {
throw new NotImplementedException();
}
}
Relationship GetRelationship(INode value);
}
}

14
src/AddIns/Analysis/CodeQuality/Engine/Dom/IValue.cs

@ -0,0 +1,14 @@ @@ -0,0 +1,14 @@
// 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 ICSharpCode.NRefactory.TypeSystem;
namespace ICSharpCode.CodeQuality.Engine.Dom
{
public interface IValue
{
string Text { get; }
}
}

44
src/AddIns/Analysis/CodeQuality/Engine/Dom/MethodNode.cs

@ -0,0 +1,44 @@ @@ -0,0 +1,44 @@
// 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 ICSharpCode.NRefactory.TypeSystem;
namespace ICSharpCode.CodeQuality.Engine.Dom
{
public class MethodNode : INode
{
public string Name {
get {
throw new NotImplementedException();
}
}
public IList<INode> Children {
get {
throw new NotImplementedException();
}
}
public IEnumerable<INode> Uses {
get {
throw new NotImplementedException();
}
}
public IEnumerable<INode> UsedBy {
get {
throw new NotImplementedException();
}
}
public Relationship GetRelationship(INode value)
{
Relationship r = new Relationship();
if (value == this)
r.AddRelationship(RelationshipType.Same);
return r;
}
}
}

47
src/AddIns/Analysis/CodeQuality/Engine/Dom/NamespaceNode.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.Collections.Generic;
using System.Linq;
using ICSharpCode.NRefactory.TypeSystem;
namespace ICSharpCode.CodeQuality.Engine.Dom
{
public class NamespaceNode : INode
{
public NamespaceNode(string name)
{
this.Name = name;
}
public string Name { get; private set; }
public IList<INode> Children {
get {
return Enumerable.Empty<INode>().ToList();
}
}
public IEnumerable<INode> Uses {
get {
throw new NotImplementedException();
}
}
public IEnumerable<INode> UsedBy {
get {
throw new NotImplementedException();
}
}
public Relationship GetRelationship(INode value)
{
Relationship r = new Relationship();
if (value == this)
r.AddRelationship(RelationshipType.Same);
return r;
}
}
}

44
src/AddIns/Analysis/CodeQuality/Engine/Dom/PropertyNode.cs

@ -0,0 +1,44 @@ @@ -0,0 +1,44 @@
// 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 ICSharpCode.NRefactory.TypeSystem;
namespace ICSharpCode.CodeQuality.Engine.Dom
{
public class PropertyNode : INode
{
public string Name {
get {
throw new NotImplementedException();
}
}
public IList<INode> Children {
get {
throw new NotImplementedException();
}
}
public IEnumerable<INode> Uses {
get {
throw new NotImplementedException();
}
}
public IEnumerable<INode> UsedBy {
get {
throw new NotImplementedException();
}
}
public Relationship GetRelationship(INode value)
{
Relationship r = new Relationship();
if (value == this)
r.AddRelationship(RelationshipType.Same);
return r;
}
}
}

60
src/AddIns/Analysis/CodeQuality/Engine/Dom/Relationship.cs

@ -0,0 +1,60 @@ @@ -0,0 +1,60 @@
// 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.Text;
using ICSharpCode.NRefactory.TypeSystem;
namespace ICSharpCode.CodeQuality.Engine.Dom
{
/// <summary>
/// Description of Relationship.
/// </summary>
public class Relationship : IValue
{
public ISet<RelationshipType> Relationships { get; private set; }
public int OccurrenceCount { get; private set; }
public string Text { get { return OccurrenceCount.ToString(); } }
public INode To { get; set; }
public INode From { get; set; }
public Relationship()
{
Relationships = new HashSet<RelationshipType>();
}
public void AddRelationship(RelationshipType type)
{
if (type == RelationshipType.UseThis || type == RelationshipType.UsedBy)
OccurrenceCount++;
Relationships.Add(type);
}
public override string ToString()
{
var builder = new StringBuilder();
foreach (var relationship in Relationships)
builder.Append(relationship + " ");
builder.Append(OccurrenceCount);
return builder.ToString();
}
}
public enum RelationshipType
{
OneWayTo,
UseThis,
UsedBy,
Same,
Contains,
None
}
}

46
src/AddIns/Analysis/CodeQuality/Engine/Dom/TypeNode.cs

@ -0,0 +1,46 @@ @@ -0,0 +1,46 @@
// 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 ICSharpCode.NRefactory.TypeSystem;
namespace ICSharpCode.CodeQuality.Engine.Dom
{
public class TypeNode : INode
{
public ITypeDefinition TypeDefinition { get; private set; }
public string Name {
get {
throw new NotImplementedException();
}
}
public IList<INode> Children {
get {
throw new NotImplementedException();
}
}
public IEnumerable<INode> Uses {
get {
throw new NotImplementedException();
}
}
public IEnumerable<INode> UsedBy {
get {
throw new NotImplementedException();
}
}
public Relationship GetRelationship(INode value)
{
Relationship r = new Relationship();
if (value == this)
r.AddRelationship(RelationshipType.Same);
return r;
}
}
}

32
src/AddIns/Analysis/CodeQuality/Gui/Controls/DependencyMatrix.cs

@ -0,0 +1,32 @@ @@ -0,0 +1,32 @@
// 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 System.Text;
using ICSharpCode.CodeQuality.Engine.Dom;
namespace ICSharpCode.CodeQuality.Gui
{
public class DependencyMatrix : VisibleMatrix<INode, Relationship>
{
protected override Relationship GetCellValue(int rowIndex, int columnIndex)
{
var toRelationship = HeaderRows[rowIndex].Value.GetRelationship(HeaderColumns[columnIndex].Value);
var fromRelationship = HeaderColumns[columnIndex].Value.GetRelationship(HeaderRows[rowIndex].Value);
toRelationship.From = HeaderRows[rowIndex].Value;
toRelationship.To = HeaderColumns[columnIndex].Value;
// add other way
foreach (var relationship in fromRelationship.Relationships) {
if (relationship == RelationshipType.UseThis)
toRelationship.AddRelationship(RelationshipType.UsedBy);
}
return toRelationship;
}
}
}

20
src/AddIns/Analysis/CodeQuality/Gui/Controls/DependencyMatrixControl.cs

@ -0,0 +1,20 @@ @@ -0,0 +1,20 @@
// 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 System.Linq.Expressions;
using System.Text;
using System.Windows;
using System.Windows.Controls.Primitives;
using ICSharpCode.CodeQuality.Engine.Dom;
namespace ICSharpCode.CodeQuality.Gui
{
public class DependencyMatrixControl : MatrixControl<VisibleMatrix<INode, Relationship>, INode, Relationship>
{
}
}

100
src/AddIns/Analysis/CodeQuality/Gui/Controls/Matrix.cs

@ -0,0 +1,100 @@ @@ -0,0 +1,100 @@
// 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 System.Text;
namespace ICSharpCode.CodeQuality.Gui
{
public abstract class Matrix<TItem, TValue>
{
protected List<Cell<TItem>> headerRows;
protected List<Cell<TItem>> headerColumns;
public virtual List<Cell<TItem>> HeaderRows
{
get {
return headerRows;
}
}
public virtual List<Cell<TItem>> HeaderColumns
{
get {
return headerColumns;
}
}
private DoubleKeyDictionary<TItem, TItem, TValue> cache;
protected Matrix()
{
headerRows = new List<Cell<TItem>>();
headerColumns = new List<Cell<TItem>>();
cache = new DoubleKeyDictionary<TItem, TItem, TValue>();
}
public void AddRow(TItem value)
{
headerRows.Add(new Cell<TItem>(value));
}
public void AddColumn(TItem value)
{
headerColumns.Add(new Cell<TItem>(value));
}
private TValue GetFromCache(TItem rowIndex, TItem columnIndex)
{
return cache[rowIndex, columnIndex];
}
private void SaveToCache(TItem rowIndex, TItem columnIndex, TValue result)
{
cache.Add(rowIndex, columnIndex, result);
}
public TValue this[int rowIndex, int columnIndex]
{
get
{
if (rowIndex > HeaderRows.Count || rowIndex < 0 ||
columnIndex > HeaderColumns.Count || columnIndex < 0)
return default(TValue);
var from = HeaderRows[rowIndex].Value;
var to = HeaderColumns[columnIndex].Value;
var cacheResult = GetFromCache(from, to);
if (cacheResult != null)
return cacheResult;
var result = GetCellValue(rowIndex, columnIndex);
SaveToCache(from, to, result);
return result;
}
}
public abstract void SetVisibleItems(HeaderType type, ICollection<TItem> visibleItems);
protected abstract TValue GetCellValue(int rowIndex, int columnIndex);
}
public class Cell<TItem>
{
public TItem Value { get; set; }
public bool Visible { get; set; }
public Cell(TItem value)
{
Value = value;
}
}
public enum HeaderType
{
Columns,
Rows
}
}

522
src/AddIns/Analysis/CodeQuality/Gui/Controls/MatrixControl.cs

@ -0,0 +1,522 @@ @@ -0,0 +1,522 @@
// 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.Drawing.Drawing2D;
using System.Linq;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Controls.Primitives;
using System.Windows.Interop;
using System.Windows.Media;
using System.Windows.Media.Imaging;
using ICSharpCode.CodeQuality.Engine.Dom;
using PointF = System.Drawing.PointF;
namespace ICSharpCode.CodeQuality.Gui
{
public class MatrixControl<TMatrix, TItem, TValue> : FrameworkElement, IScrollInfo
where TValue : IValue
where TMatrix : Matrix<TItem, TValue>
{
public event EventHandler<HoveredCellEventArgs<TValue>> HoveredCellChanged;
private Dictionary<string, ImageSource> imgs = new Dictionary<string, ImageSource>();
private Coords currentCell = new Coords(0, 0);
private string font;
private bool canHorizontalScroll = true;
private bool canVerticalScroll = true;
private Size extent = new Size(0, 0);
private Size viewport = new Size(0, 0);
private Point offset;
// will be loaded from Matrix
private int matrixWidth = 0;
private int matrixHeight = 0;
private int fontSize = 0;
private int penSize = 0;
protected int PageSizeWidth { get; set; }
protected int PageSizeHeight { get; set; }
public TMatrix Matrix { get; set; }
public int CellHeight { get; set; }
public int CellWidth { get; set; }
public HoveredCell<TValue> HoveredCell { get; set; }
public bool RenderZeroes { get; set; }
public IColorizer<TValue> Colorizer { get; set; }
public MatrixControl()
{
CellHeight = CellWidth = 18;
matrixWidth = 0;
matrixHeight = 0;
fontSize = CellHeight / 3;
penSize = 1;
font = "Verdana";
HoveredCell = new HoveredCell<TValue>();
}
public void SetVisibleItems(HeaderType type, ICollection<TItem> visibleItems)
{
Matrix.SetVisibleItems(type, visibleItems);
matrixHeight = Matrix.HeaderRows.Count;
matrixWidth = Matrix.HeaderColumns.Count;
bool changedCoords = false;
if (currentCell.X > matrixHeight) {
currentCell = new Coords(matrixHeight - 1, currentCell.Y);
changedCoords = true;
}
if (currentCell.Y > matrixWidth) {
currentCell = new Coords(currentCell.X, matrixWidth - 1);
changedCoords = true;
}
if (changedCoords) {
SetHoveredCell();
}
if (matrixHeight >= 0 && matrixWidth >= 0)
InvalidateVisual();
}
public void HighlightLine(HeaderType type, INode node)
{
var items = type == HeaderType.Columns ? Matrix.HeaderColumns : Matrix.HeaderRows;
for (int i = 0; i < items.Count; i++) {
if (items[i].Value.Equals(node)) {
if (currentCell.X == i && type == HeaderType.Rows)
return;
if (currentCell.Y == i && type == HeaderType.Columns)
return;
currentCell = type == HeaderType.Columns ?
new Coords(i, currentCell.Y) :
new Coords(currentCell.X, i);
SetHoveredCell();
InvalidateVisual();
return;
}
}
}
protected override void OnMouseMove(System.Windows.Input.MouseEventArgs e)
{
base.OnMouseMove(e);
var point = e.GetPosition(this);
if (point.X < matrixWidth * CellWidth
&& point.Y < matrixHeight * CellHeight)
currentCell = new Coords(
(int)((point.X + offset.X) / CellWidth),
(int)((point.Y + offset.Y) / CellHeight));
// else // if we are out of matrix just use last cell
// currentCell = new Coords(-1, -1);
if (currentCell.X != HoveredCell.RowIndex ||
currentCell.Y != HoveredCell.ColumnIndex)
{
InvalidateVisual();
SetHoveredCell();
}
}
protected override void OnMouseDown(System.Windows.Input.MouseButtonEventArgs e)
{
base.OnMouseDown(e);
Relationship relationship = HoveredCell.Value as Relationship;
Console.WriteLine("To: " + relationship.To.Name);
Console.WriteLine("From:" + relationship.From.Name);
}
protected void SetHoveredCell()
{
HoveredCell.RowIndex = currentCell.Y;
HoveredCell.ColumnIndex = currentCell.X;
HoveredCell.Value = Matrix[HoveredCell.RowIndex, HoveredCell.ColumnIndex];
if (HoveredCellChanged != null)
HoveredCellChanged(this, new HoveredCellEventArgs<TValue>(HoveredCell));
}
protected override void OnRender(DrawingContext drawingContext)
{
base.OnRender(drawingContext);
// how much space we got for cells
var maxWidth = ((int) viewport.Width / CellWidth) + 1;
var maxHeight = ((int) viewport.Height / CellHeight) + 1;
// how many cells we will draw
// sometimes happens when half of cell is hidden in scroll so text isnt drawn
// so lets drawn one more cell
var cellsHorizontally = maxWidth >= matrixWidth ? matrixWidth : maxWidth + 1;
var cellsVertically = maxHeight >= matrixHeight ? matrixHeight : maxHeight + 1;
PageSizeWidth = cellsHorizontally;
PageSizeHeight = cellsVertically;
// number of cell which arent visible
var scaledOffsetX = (int)offset.X / CellWidth;
var scaledOffsetY = (int)offset.Y / CellHeight;
// sets how much of cell on border should be drawn
var offsetDiffX = offset.X - scaledOffsetX * CellWidth;
var offsetDiffY = offset.Y - scaledOffsetY * CellHeight;
// background
var background = new Rect(0, 0, cellsHorizontally * CellWidth, cellsVertically * CellHeight);
var backgroundColor = new SolidColorBrush(Colors.Yellow);
backgroundColor.Freeze();
drawingContext.DrawRectangle(backgroundColor, null, background);
var currentXLine = (currentCell.X - scaledOffsetX) * CellWidth - offsetDiffX;
var currentYLine = (currentCell.Y - scaledOffsetY) * CellHeight - offsetDiffY;
// hovering
if (currentCell.X >= 0 || currentCell.Y >= 0) {
// hover y line
var rect = new Rect(0,
currentYLine,
CellWidth * cellsHorizontally,
CellHeight);
var brush = new SolidColorBrush(Colors.GreenYellow);
brush.Freeze();
drawingContext.DrawRectangle(brush, null, rect);
// hover x line
rect = new Rect(currentXLine,
0,
CellWidth,
CellHeight * cellsVertically);
brush = new SolidColorBrush(Colors.GreenYellow);
brush.Freeze();
drawingContext.DrawRectangle(brush, null, rect);
// hover cell
rect = new Rect(
(currentCell.X - scaledOffsetX) * CellWidth - offsetDiffX,
(currentCell.Y - scaledOffsetY) * CellHeight - offsetDiffY,
CellWidth,
CellHeight);
brush = new SolidColorBrush(Colors.Red);
brush.Freeze();
drawingContext.DrawRectangle(brush, null, rect);
}
// text
for (int i = 0; i < cellsHorizontally; i++) {
for (int j = 0; j < cellsVertically; j++) { // dont draw text in unavailables places
int rowIndex = j + scaledOffsetY;
int columnIndex = i + scaledOffsetX;
// adjust scales
rowIndex = rowIndex >= Matrix.HeaderRows.Count ? rowIndex - 1 : rowIndex;
columnIndex = columnIndex >= Matrix.HeaderColumns.Count ? columnIndex - 1 : columnIndex;
var value = Matrix[rowIndex, columnIndex];
if (Colorizer != null) {
var rect = new Rect(
i * CellWidth - offsetDiffX,
j * CellHeight - offsetDiffY,
CellWidth,
CellHeight);
SolidColorBrush brush = null;
if ((i * CellWidth - offsetDiffX) == currentXLine ||
((j * CellHeight - offsetDiffY) == currentYLine)) {
var color = Colors.GreenYellow;
if (currentCell.X == i && currentCell.Y == j) {
color = color.MixedWith(Colors.Red);
}
brush = Colorizer.GetColorBrushMixedWith(color, value);
}
else
brush = Colorizer.GetColorBrush(value);
drawingContext.DrawRectangle(brush, null, rect);
}
if (!RenderZeroes && value != null && value.Text != "0") // rendering zeroes would be distracting
drawingContext.DrawImage(
CreateText(value.Text),
new Rect(i * CellWidth - offsetDiffX, j * CellHeight - offsetDiffY, CellWidth, CellHeight));
}
}
// grid
var pen = new Pen(Brushes.Black, penSize);
pen.Freeze();
// grid x
for (int i = 0; i <= cellsHorizontally; i++)
drawingContext.DrawLine(pen,
new Point(i * CellWidth - offsetDiffX, 0),
new Point(i * CellWidth - offsetDiffX,
cellsVertically * CellWidth));
// grid y
for (int i = 0; i <= cellsVertically; i++)
drawingContext.DrawLine(pen,
new Point(0, i * CellHeight - offsetDiffY),
new Point(cellsHorizontally * CellHeight,
i * CellHeight - offsetDiffY));
}
public ImageSource CreateText(string text)
{
if (imgs.ContainsKey(text))
return imgs[text];
var bmp = new System.Drawing.Bitmap(CellWidth, CellHeight);
var g = System.Drawing.Graphics.FromImage(bmp);
g.SmoothingMode = SmoothingMode.AntiAlias;
g.TextRenderingHint = System.Drawing.Text.TextRenderingHint.AntiAlias;
var fontOjb = new System.Drawing.Font(font, fontSize);
var size = g.MeasureString(text, fontOjb);
var spanWidth = (CellWidth - size.Width) / 2;
var spanHeight = (CellHeight - size.Height) / 2;
g.DrawString(text, fontOjb, System.Drawing.Brushes.Black, new PointF(spanWidth, spanHeight));
g.Dispose();
var bitmap = bmp.GetHbitmap();
var img = Imaging.CreateBitmapSourceFromHBitmap(bitmap,
IntPtr.Zero,
Int32Rect.Empty,
BitmapSizeOptions.FromWidthAndHeight(bmp.Width, bmp.Height));
img.Freeze();
imgs.Add(text, img);
Utils.DeleteObject(bitmap);
return img;
}
public bool CanVerticallyScroll
{
get { return canVerticalScroll; }
set { canVerticalScroll = value; }
}
public bool CanHorizontallyScroll
{
get { return canHorizontalScroll; }
set { canHorizontalScroll = value; }
}
/// <summary>
/// Width of entire component
/// </summary>
public double ExtentWidth
{
get { return extent.Width; }
}
/// <summary>
/// Height of entire component
/// </summary>
public double ExtentHeight
{
get { return extent.Height; }
}
/// <summary>
/// Width of available area
/// </summary>
public double ViewportWidth
{
get { return viewport.Width; }
}
/// <summary>
/// Height of available area
/// </summary>
public double ViewportHeight
{
get { return viewport.Height; }
}
/// <summary>
/// Where is scrollbar located on X
/// </summary>
public double HorizontalOffset
{
get { return offset.X; }
}
/// <summary>
/// Where is scrollbar located on Y
/// </summary>
public double VerticalOffset
{
get { return offset.Y; }
}
public ScrollViewer ScrollOwner { get; set; }
public void LineUp()
{
SetVerticalOffset(VerticalOffset - CellHeight);
}
public void LineDown()
{
SetVerticalOffset(VerticalOffset + CellHeight);
}
public void LineLeft()
{
SetHorizontalOffset(HorizontalOffset - CellWidth);
}
public void LineRight()
{
SetHorizontalOffset(HorizontalOffset + CellWidth);
}
public void PageUp()
{
SetVerticalOffset(VerticalOffset - CellHeight * PageSizeHeight);
}
public void PageDown()
{
SetVerticalOffset(VerticalOffset + CellHeight * PageSizeHeight);
}
public void PageLeft()
{
SetHorizontalOffset(HorizontalOffset - CellWidth * PageSizeWidth);
}
public void PageRight()
{
SetHorizontalOffset(HorizontalOffset + CellWidth * PageSizeWidth);
}
public void MouseWheelUp()
{
SetVerticalOffset(VerticalOffset - CellHeight);
}
public void MouseWheelDown()
{
SetVerticalOffset(VerticalOffset + CellHeight);
}
public void MouseWheelLeft()
{
SetVerticalOffset(HorizontalOffset - CellWidth);
}
public void MouseWheelRight()
{
SetVerticalOffset(HorizontalOffset + CellWidth);
}
public void SetHorizontalOffset(double offset)
{
if (offset == this.offset.X) return;
this.offset.X = Math.Round(offset / CellWidth) * CellWidth;
InvalidateVisual();
}
public void SetVerticalOffset(double offset)
{
if (offset == this.offset.Y) return;
this.offset.Y = Math.Round(offset / CellHeight) * CellHeight;
InvalidateVisual();
}
public Rect MakeVisible(Visual visual, Rect rectangle)
{
throw new NotImplementedException();
}
protected override Size MeasureOverride(Size availableSize)
{
VerifyScrollData(availableSize, new Size(matrixWidth * CellWidth, matrixHeight * CellHeight));
return viewport;
}
protected override Size ArrangeOverride(Size finalSize)
{
VerifyScrollData(finalSize, new Size(matrixWidth * CellWidth, matrixHeight * CellHeight));
return finalSize;
}
protected void VerifyScrollData(Size viewport, Size extent)
{
if (double.IsInfinity(viewport.Width))
viewport.Width = extent.Width;
if (double.IsInfinity(viewport.Height))
viewport.Height = extent.Height;
// if viewport changes so recalculates offsets
offset.X = Math.Max(0, Math.Min(offset.X, ExtentWidth - ViewportWidth));
offset.Y = Math.Max(0, Math.Min(offset.Y, ExtentHeight - ViewportHeight));
this.extent = extent;
this.viewport = viewport;
if (ScrollOwner != null)
ScrollOwner.InvalidateScrollInfo();
}
private struct Coords
{
public int Y { get; private set; }
public int X { get; private set; }
public Coords(int x, int y) : this()
{
X = x;
Y = y;
}
}
}
public class HoveredCell<TValue>
{
public int RowIndex { get; set; }
public int ColumnIndex { get; set; }
public TValue Value { get; set; }
}
public class HoveredCellEventArgs<TValue> : EventArgs
{
public HoveredCell<TValue> HoveredCell { get; set; }
public HoveredCellEventArgs(HoveredCell<TValue> cell)
{
HoveredCell = cell;
}
}
}

46
src/AddIns/Analysis/CodeQuality/Gui/Controls/VisibleMatrix.cs

@ -0,0 +1,46 @@ @@ -0,0 +1,46 @@
// 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;
namespace ICSharpCode.CodeQuality.Gui
{
/// <summary>
/// Description of VisibleMatrix.
/// </summary>
public abstract class VisibleMatrix<TItem, TValue> : Matrix<TItem, TValue>
{
protected List<Cell<TItem>> visibleHeaderRows;
protected List<Cell<TItem>> visibleHeaderColumns;
public override List<Cell<TItem>> HeaderRows
{
get {
return visibleHeaderRows;
}
}
public override List<Cell<TItem>> HeaderColumns
{
get {
return visibleHeaderColumns;
}
}
public override void SetVisibleItems(HeaderType type, ICollection<TItem> visibleItems)
{
var items = type == HeaderType.Columns ? headerColumns : headerRows;
foreach (var item in items)
{
var foundItem = visibleItems.Where(n => n.Equals(item.Value)).SingleOrDefault();
item.Visible = foundItem != null;
}
visibleHeaderRows = headerRows.Where(c => c.Visible).ToList();
visibleHeaderColumns = headerColumns.Where(c => c.Visible).ToList();
}
}
}

42
src/AddIns/Analysis/CodeQuality/Gui/DependencyMatrixView.xaml

@ -0,0 +1,42 @@ @@ -0,0 +1,42 @@
<UserControl x:Class="ICSharpCode.CodeQuality.Gui.DependencyMatrixView"
xmlns:gui="clr-namespace:ICSharpCode.CodeQuality.Gui"
xmlns:tv="http://icsharpcode.net/sharpdevelop/treeview"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml">
<Grid>
<Grid.RowDefinitions>
<RowDefinition Height="1*" />
<RowDefinition Height="Auto" />
<RowDefinition Height="2*" />
</Grid.RowDefinitions>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="1*" />
<ColumnDefinition Width="Auto" />
<ColumnDefinition Width="2*" />
</Grid.ColumnDefinitions>
<!-- Top TreeView -->
<tv:SharpTreeView Name="topTree" Grid.Column="2" ScrollViewer.ScrollChanged="ViewScrollChanged" ScrollViewer.VerticalScrollBarVisibility="Hidden">
<tv:SharpTreeView.LayoutTransform>
<RotateTransform Angle="-90" />
</tv:SharpTreeView.LayoutTransform>
</tv:SharpTreeView>
<GridSplitter Grid.Column="1"
Grid.RowSpan="3"
HorizontalAlignment="Center"
VerticalAlignment="Stretch"
ShowsPreview="True"
Width="1" />
<GridSplitter Grid.Row="1"
Grid.ColumnSpan="3"
VerticalAlignment="Center"
HorizontalAlignment="Stretch"
ShowsPreview="True"
Height="1" />
<!-- Left TreeView -->
<tv:SharpTreeView Name="leftTree" Grid.Row="2" ScrollViewer.ScrollChanged="ViewScrollChanged" ScrollViewer.VerticalScrollBarVisibility="Hidden">
</tv:SharpTreeView>
<ScrollViewer HorizontalScrollBarVisibility="Auto" VerticalScrollBarVisibility="Auto" Grid.Row="2" Grid.Column="2">
<gui:DependencyMatrixControl x:Name="matrix" ScrollViewer.ScrollChanged="ViewScrollChanged" />
</ScrollViewer>
</Grid>
</UserControl>

118
src/AddIns/Analysis/CodeQuality/Gui/DependencyMatrixView.xaml.cs

@ -0,0 +1,118 @@ @@ -0,0 +1,118 @@
// 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.Collections.Specialized;
using System.Linq;
using System.Text;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Data;
using System.Windows.Documents;
using System.Windows.Input;
using System.Windows.Media;
using System.Windows.Threading;
using ICSharpCode.CodeQuality.Engine.Dom;
using ICSharpCode.SharpDevelop;
namespace ICSharpCode.CodeQuality.Gui
{
/// <summary>
/// Interaction logic for DependencyMatrixView.xaml
/// </summary>
public partial class DependencyMatrixView : UserControl
{
public DependencyMatrixView()
{
InitializeComponent();
topTree.Root = new ICSharpCode.TreeView.SharpTreeNode();
leftTree.Root = new ICSharpCode.TreeView.SharpTreeNode();
matrix.Colorizer = new DependencyColorizer();
}
public void Update(IEnumerable<INode> nodes)
{
Extensions.FillTree(topTree, nodes);
Extensions.FillTree(leftTree, nodes);
var leftCol = leftTree.Items.SourceCollection as INotifyCollectionChanged;
leftCol.CollectionChanged += BuildLeftINodeList;
var topCol = topTree.Items.SourceCollection as INotifyCollectionChanged;
topCol.CollectionChanged += BuildTopINodeList;
var matrix = new DependencyMatrix();
AddChildrenToMatrix(matrix, nodes);
this.matrix.Matrix = matrix;
}
void AddChildrenToMatrix(DependencyMatrix matrix, IEnumerable<INode> nodes)
{
foreach (var node in nodes) {
matrix.AddColumn(node);
matrix.AddRow(node);
AddChildrenToMatrix(matrix, node.Children);
}
}
void ViewScrollChanged(object sender, ScrollChangedEventArgs e)
{
ScrollViewer scrollViewer = e.OriginalSource as ScrollViewer;
ScrollViewer topTree = this.topTree.GetScrollViewer();
ScrollViewer leftTree = this.leftTree.GetScrollViewer();
if (scrollViewer.Content == matrix) {
scrollViewer.SynchronizeScroll(topTree, ScrollSyncOption.HorizontalToVertical);
scrollViewer.SynchronizeScroll(leftTree, ScrollSyncOption.Vertical);
}
}
#region Update MatrixControl
bool rebuildLeftNodeListRequested;
void BuildLeftINodeList(object sender, NotifyCollectionChangedEventArgs e)
{
if (rebuildLeftNodeListRequested)
return;
rebuildLeftNodeListRequested = true;
Dispatcher.BeginInvoke(DispatcherPriority.DataBind, new Action(SetVisibleItemsForRows));
}
void SetVisibleItemsForRows()
{
List<INode> leftNodes = new List<INode>();
foreach (MatrixTreeNode node in leftTree.Items.OfType<MatrixTreeNode>()) {
var n = node.Node;
leftNodes.Add(n);
}
rebuildLeftNodeListRequested = false;
matrix.SetVisibleItems(HeaderType.Rows, leftNodes);
}
bool rebuildTopNodeListRequested;
void BuildTopINodeList(object sender, NotifyCollectionChangedEventArgs e)
{
if (rebuildTopNodeListRequested)
return;
rebuildTopNodeListRequested = true;
Dispatcher.BeginInvoke(DispatcherPriority.DataBind, new Action(SetVisibleItemsForColumns));
}
void SetVisibleItemsForColumns()
{
List<INode> topNodes = new List<INode>();
foreach (MatrixTreeNode node in topTree.Items.OfType<MatrixTreeNode>()) {
var n = node.Node;
topNodes.Add(n);
}
rebuildTopNodeListRequested = false;
matrix.SetVisibleItems(HeaderType.Columns, topNodes);
}
#endregion
}
}

9
src/AddIns/Analysis/CodeQuality/Gui/MainView.xaml

@ -1,13 +1,14 @@ @@ -1,13 +1,14 @@
<UserControl x:Class="ICSharpCode.CodeQuality.Gui.MainView"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml">
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:gui="clr-namespace:ICSharpCode.CodeQuality.Gui"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml">
<DockPanel>
<ToolBar DockPanel.Dock="Top">
<Button>Add Assembly</Button>
<Button Click="AddAssemblyClick">Add Assembly</Button>
</ToolBar>
<TabControl>
<TabItem Header="Dependency Matrix">
<gui:DependencyMatrixView x:Name="matrix" />
</TabItem>
</TabControl>
</DockPanel>

21
src/AddIns/Analysis/CodeQuality/Gui/MainView.xaml.cs

@ -10,6 +10,8 @@ using System.Windows.Data; @@ -10,6 +10,8 @@ using System.Windows.Data;
using System.Windows.Documents;
using System.Windows.Input;
using System.Windows.Media;
using ICSharpCode.CodeQuality.Engine;
using Microsoft.Win32;
namespace ICSharpCode.CodeQuality.Gui
{
@ -18,9 +20,28 @@ namespace ICSharpCode.CodeQuality.Gui @@ -18,9 +20,28 @@ namespace ICSharpCode.CodeQuality.Gui
/// </summary>
public partial class MainView : UserControl
{
AssemblyAnalyzer context;
public MainView()
{
InitializeComponent();
context = new AssemblyAnalyzer();
this.DataContext = context;
}
void AddAssemblyClick(object sender, RoutedEventArgs e)
{
OpenFileDialog fileDialog = new OpenFileDialog {
Filter = "Component Files (*.dll, *.exe)|*.dll;*.exe",
Multiselect = true
};
if (fileDialog.ShowDialog() != true || fileDialog.FileNames.Length == 0)
return;
context.AddAssemblyFiles(fileDialog.FileNames);
matrix.Update(context.Analyze());
}
}
}

34
src/AddIns/Analysis/CodeQuality/Gui/MatrixTreeNode.cs

@ -0,0 +1,34 @@ @@ -0,0 +1,34 @@
// 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 ICSharpCode.CodeQuality.Engine.Dom;
using ICSharpCode.TreeView;
namespace ICSharpCode.CodeQuality.Gui
{
/// <summary>
/// Description of MatrixTreeNode.
/// </summary>
public class MatrixTreeNode : SharpTreeNode
{
INode node;
public INode Node {
get { return node; }
}
public MatrixTreeNode(INode node)
{
this.node = node;
}
public override object Icon {
get { return NodeIconService.GetIcon(node); }
}
public override object Text {
get { return node.Name; }
}
}
}

195
src/AddIns/Analysis/CodeQuality/Gui/NodeIconService.cs

@ -0,0 +1,195 @@ @@ -0,0 +1,195 @@
// 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 System.Text;
using System.Windows.Media.Imaging;
using ICSharpCode.CodeQuality.Engine.Dom;
using ICSharpCode.Core.Presentation;
using ICSharpCode.NRefactory.TypeSystem;
namespace ICSharpCode.CodeQuality.Gui
{
public static class NodeIconService
{
static readonly BitmapSource NamespaceNode = GetImage("Icons.16x16.NameSpace");
static readonly BitmapSource Assembly = GetImage("Icons.16x16.Assembly");
static readonly BitmapSource Class = GetImage("Icons.16x16.Class");
static readonly BitmapSource InternalClass = GetImage("Icons.16x16.InternalClass");
static readonly BitmapSource ProtectedClass = GetImage("Icons.16x16.ProtectedClass");
static readonly BitmapSource PrivateClass = GetImage("Icons.16x16.PrivateClass");
static readonly BitmapSource Struct = GetImage("Icons.16x16.Struct");
static readonly BitmapSource InternalStruct = GetImage("Icons.16x16.InternalStruct");
static readonly BitmapSource ProtectedStruct = GetImage("Icons.16x16.ProtectedStruct");
static readonly BitmapSource PrivateStruct = GetImage("Icons.16x16.PrivateStruct");
static readonly BitmapSource Interface = GetImage("Icons.16x16.Interface");
static readonly BitmapSource InternalInterface = GetImage("Icons.16x16.InternalInterface");
static readonly BitmapSource ProtectedInterface = GetImage("Icons.16x16.ProtectedInterface");
static readonly BitmapSource PrivateInterface = GetImage("Icons.16x16.PrivateInterface");
static readonly BitmapSource Enum = GetImage("Icons.16x16.Enum");
static readonly BitmapSource InternalEnum = GetImage("Icons.16x16.InternalEnum");
static readonly BitmapSource ProtectedEnum = GetImage("Icons.16x16.ProtectedEnum");
static readonly BitmapSource PrivateEnum = GetImage("Icons.16x16.PrivateEnum");
static readonly BitmapSource Delegate = GetImage("Icons.16x16.Delegate");
static readonly BitmapSource InternalDelegate = GetImage("Icons.16x16.InternalDelegate");
static readonly BitmapSource ProtectedDelegate = GetImage("Icons.16x16.ProtectedDelegate");
static readonly BitmapSource PrivateDelegate = GetImage("Icons.16x16.PrivateDelegate");
static readonly BitmapSource MethodNode = GetImage("Icons.16x16.Method");
static readonly BitmapSource ProtectedMethod = GetImage("Icons.16x16.ProtectedMethod");
static readonly BitmapSource PrivateMethod = GetImage("Icons.16x16.PrivateMethod");
static readonly BitmapSource Property = GetImage("Icons.16x16.Property");
static readonly BitmapSource ProtectedProperty = GetImage("Icons.16x16.ProtectedProperty");
static readonly BitmapSource PrivateProperty = GetImage("Icons.16x16.PrivateProperty");
static readonly BitmapSource Field = GetImage("Icons.16x16.Field");
static readonly BitmapSource ProtectedField = GetImage("Icons.16x16.ProtectedField");
static readonly BitmapSource PrivateField = GetImage("Icons.16x16.PrivateField");
static readonly BitmapSource Event = GetImage("Icons.16x16.Event");
static readonly BitmapSource ProtectedEvent = GetImage("Icons.16x16.ProtectedEvent");
static readonly BitmapSource PrivateEvent = GetImage("Icons.16x16.PrivateEvent");
static readonly BitmapSource ConstantField = GetImage("Icons.16x16.Literal");
static BitmapSource GetImage(string name)
{
try {
return PresentationResourceService.GetBitmapSource(name);
} catch (Exception) {
return null; // image isn't needed necessarily
}
}
public static BitmapSource GetIcon(FieldNode field)
{
// if (field.Field.IsPrivate)
// return PrivateField;
// if (field.Field.IsProtected)
// return ProtectedField;
// if (field.Field.IsConst)
// return ConstantField;
return Field;
}
public static BitmapSource GetIcon(INode node)
{
if (node is AssemblyNode)
return GetIcon((AssemblyNode)node);
if (node is NamespaceNode)
return GetIcon((NamespaceNode)node);
if (node is TypeNode)
return GetIcon((TypeNode)node);
if (node is MethodNode)
return GetIcon((MethodNode)node);
if (node is FieldNode)
return GetIcon((FieldNode)node);
if (node is PropertyNode)
return GetIcon((PropertyNode)node);
if (node is EventNode)
return GetIcon((EventNode)node);
return null;
}
public static BitmapSource GetIcon(EventNode node)
{
// if (node.Event.IsPrivate)
// return PrivateEventField;
// if (node.Event.IsProtected)
// return ProtectedEventField;
return Event;
}
public static BitmapSource GetIcon(MethodNode method)
{
// if (method.Method.IsPrivate)
// return PrivateMethod;
// if (method.Method.IsProtected)
// return ProtectedMethod;
// if (method.IsGetter || method.IsSetter)
// {
// if (method.IsPublic)
// return PropertyMethod;
// if (method.IsPrivate)
// return PrivatePropertyMethod;
// if (method.IsProtected)
// return ProtectedPropertyMethod;
// }
return MethodNode;
}
public static BitmapSource GetIcon(PropertyNode property)
{
return Property;
}
public static BitmapSource GetIcon(AssemblyNode module)
{
return Assembly;
}
public static BitmapSource GetIcon(NamespaceNode ns)
{
return NamespaceNode;
}
public static BitmapSource GetIcon(TypeNode type)
{
switch (type.TypeDefinition.Kind) {
case TypeKind.Enum:
if (type.TypeDefinition.IsPublic)
return Enum;
if (type.TypeDefinition.IsProtected)
return ProtectedEnum;
if (type.TypeDefinition.IsInternal)
return InternalEnum;
return PrivateEnum;
case TypeKind.Struct:
if (type.TypeDefinition.IsPublic)
return Struct;
if (type.TypeDefinition.IsProtected)
return ProtectedStruct;
if (type.TypeDefinition.IsInternal)
return InternalStruct;
return PrivateStruct;
case TypeKind.Interface:
if (type.TypeDefinition.IsPublic)
return Interface;
if (type.TypeDefinition.IsProtected)
return ProtectedInterface;
if (type.TypeDefinition.IsInternal)
return InternalInterface;
return PrivateInterface;
case TypeKind.Delegate:
if (type.TypeDefinition.IsPublic)
return Delegate;
if (type.TypeDefinition.IsProtected)
return ProtectedDelegate;
if (type.TypeDefinition.IsInternal)
return InternalDelegate;
return PrivateDelegate;
default:
if (type.TypeDefinition.IsPublic)
return Class;
if (type.TypeDefinition.IsProtected)
return ProtectedClass;
if (type.TypeDefinition.IsInternal)
return InternalClass;
return PrivateClass;
}
}
}
}

71
src/AddIns/Analysis/CodeQuality/Utils/DependencyColorizer.cs

@ -0,0 +1,71 @@ @@ -0,0 +1,71 @@
// 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 System.Windows.Media;
using ICSharpCode.CodeQuality.Engine.Dom;
namespace ICSharpCode.CodeQuality
{
/// <summary>
/// Description of DependencyColorizer.
/// </summary>
public class DependencyColorizer : IColorizer<Relationship>
{
private Dictionary<Color, SolidColorBrush> cache;
public DependencyColorizer()
{
cache = new Dictionary<Color, SolidColorBrush>();
}
public SolidColorBrush GetColorBrush(Relationship relationship)
{
var color = GetColor(relationship);
if (cache.ContainsKey(color))
return cache[color];
var brush = new SolidColorBrush(color);
brush.Freeze();
cache[color] = brush;
return brush;
}
public Color GetColor(Relationship relationship)
{
if (relationship == null)
return Colors.Transparent;
if (relationship.Relationships.Any(r => r == RelationshipType.UseThis))
return Colors.LightBlue;
if (relationship.Relationships.Any(r => r == RelationshipType.UsedBy))
return Colors.Violet;
if (relationship.Relationships.Any(r => r == RelationshipType.Same))
return Colors.Gray;
return Colors.Transparent;
}
public SolidColorBrush GetColorBrushMixedWith(Color color, Relationship relationship)
{
var mixedColor = GetColor(relationship);
mixedColor = mixedColor.MixedWith(color);
if (cache.ContainsKey(mixedColor))
return cache[mixedColor];
var brush = new SolidColorBrush(mixedColor);
brush.Freeze();
cache[mixedColor] = brush;
return brush;
}
}
}

140
src/AddIns/Analysis/CodeQuality/Utils/DoubleKeyDictionary.cs

@ -0,0 +1,140 @@ @@ -0,0 +1,140 @@
// 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;
namespace ICSharpCode.CodeQuality
{
public class DoubleKeyDictionary<K, T, V> :
IEnumerable<DoubleKeyPairValue<K, T, V>>,
IEquatable<DoubleKeyDictionary<K, T, V>>
{
private Dictionary<T, V> innerDictionary;
public DoubleKeyDictionary()
{
OuterDictionary = new Dictionary<K, Dictionary<T, V>>();
}
private Dictionary<K, Dictionary<T, V>> OuterDictionary { get; set; }
public void Add(K key1, T key2, V value)
{
if (OuterDictionary.ContainsKey(key1)) {
if (innerDictionary.ContainsKey(key2)) {
OuterDictionary[key1][key2] = value;
}
else {
innerDictionary = OuterDictionary[key1];
innerDictionary.Add(key2, value);
OuterDictionary[key1] = innerDictionary;
}
}
else {
innerDictionary = new Dictionary<T, V>();
innerDictionary[key2] = value;
OuterDictionary.Add(key1, innerDictionary);
}
}
public V this[K index1, T index2]
{
get
{
Dictionary<T, V> value1;
OuterDictionary.TryGetValue(index1, out value1);
if (value1 == null)
return default(V);
V value2;
value1.TryGetValue(index2, out value2);
if (value2 == null)
return default(V);
return value2;
}
set
{
Add(index1, index2, value);
}
}
#region IEnumerable<DoubleKeyPairValue<K,T,V>> Members
public IEnumerator<DoubleKeyPairValue<K, T, V>> GetEnumerator()
{
foreach (KeyValuePair<K, Dictionary<T, V>> outer in OuterDictionary)
foreach (KeyValuePair<T, V> inner in outer.Value)
yield return new DoubleKeyPairValue<K, T, V>(outer.Key, inner.Key, inner.Value);
}
#endregion
#region IEnumerable Members
System.Collections.IEnumerator System.Collections.IEnumerable.GetEnumerator()
{
return GetEnumerator();
}
#endregion
#region IEquatable<DoubleKeyDictionary<K,T,V>> Members
public bool Equals(DoubleKeyDictionary<K, T, V> other)
{
if (OuterDictionary.Keys.Count != other.OuterDictionary.Keys.Count)
return false;
bool isEqual = true;
foreach (KeyValuePair<K, Dictionary<T, V>> innerItems in OuterDictionary) {
if (!other.OuterDictionary.ContainsKey(innerItems.Key))
isEqual = false;
if (!isEqual)
break;
// here we can be sure that the key is in both lists,
// but we need to check the contents of the inner dictionary
Dictionary<T, V> otherInnerDictionary = other.OuterDictionary[innerItems.Key];
foreach (KeyValuePair<T, V> innerValue in innerItems.Value) {
if (!otherInnerDictionary.ContainsValue(innerValue.Value))
isEqual = false;
if (!otherInnerDictionary.ContainsKey(innerValue.Key))
isEqual = false;
}
if (!isEqual)
break;
}
return isEqual;
}
#endregion
}
public class DoubleKeyPairValue<K, T, V>
{
public K Key1 { get; set; }
public T Key2 { get; set; }
public V Value { get; set; }
public DoubleKeyPairValue(K key1, T key2, V value) {
Key1 = key1;
Key2 = key2;
Value = value;
}
public override string ToString()
{
return Key1.ToString() + " - " + Key2.ToString() + " - " + Value.ToString();
}
}
}

77
src/AddIns/Analysis/CodeQuality/Utils/Extensions.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.Windows;
using System.Windows.Controls;
using System.Windows.Media;
using ICSharpCode.CodeQuality.Engine.Dom;
using ICSharpCode.CodeQuality.Gui;
using ICSharpCode.TreeView;
namespace ICSharpCode.CodeQuality
{
/// <summary>
/// Description of Extensions.
/// </summary>
public static class Extensions
{
public static void FillTree(SharpTreeView tree, IEnumerable<INode> rootNodes)
{
tree.Root = new SharpTreeNode();
CreateItems(rootNodes, tree.Root);
}
static void CreateItems(IEnumerable<INode> nodes, SharpTreeNode parent)
{
foreach (INode node in nodes) {
var item = new MatrixTreeNode(node);
parent.Children.Add(item);
CreateItems(node.Children, item);
}
}
public static T FindVisualChild<T>(DependencyObject obj) where T : DependencyObject
{
// depth-first Search
int count = VisualTreeHelper.GetChildrenCount(obj);
for (int i = 0; i < count; i++) {
DependencyObject child = VisualTreeHelper.GetChild(obj, i);
if (child is T)
return (T)child;
else {
T childOfChild = FindVisualChild<T>(child);
if (childOfChild != null)
return childOfChild;
}
}
return null;
}
public static TContainer GetParent<TContainer>(this DependencyObject obj) where TContainer : DependencyObject
{
if (obj == null)
return null;
while (VisualTreeHelper.GetParent(obj) != null && !(obj is TContainer))
obj = VisualTreeHelper.GetParent(obj);
return obj as TContainer;
}
public static Color MixedWith(this Color c1, Color c2)
{
var percent = .5f;
var amountFrom = 1.0f - percent;
return Color.FromArgb(
(byte)(c1.A * amountFrom + c2.A * percent),
(byte)(c1.R * amountFrom + c2.R * percent),
(byte)(c1.G * amountFrom + c2.G * percent),
(byte)(c1.B * amountFrom + c2.B * percent));
}
}
}

20
src/AddIns/Analysis/CodeQuality/Utils/IColorizer.cs

@ -0,0 +1,20 @@ @@ -0,0 +1,20 @@
// 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.Windows.Media;
namespace ICSharpCode.CodeQuality
{
/// <summary>
/// Description of IColorizer.
/// </summary>
public interface IColorizer<TValue>
{
SolidColorBrush GetColorBrush(TValue value);
SolidColorBrush GetColorBrushMixedWith(Color color, TValue value);
Color GetColor(TValue value);
}
}

17
src/AddIns/Analysis/CodeQuality/Utils/Utils.cs

@ -0,0 +1,17 @@ @@ -0,0 +1,17 @@
// 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.Runtime.InteropServices;
namespace ICSharpCode.CodeQuality
{
/// <summary>
/// Description of Utils.
/// </summary>
public class Utils
{
[DllImport("gdi32.dll")]
public static extern bool DeleteObject(IntPtr hObject);
}
}

52
src/Main/Base/Project/Src/Util/ScrollUtils.cs

@ -20,8 +20,8 @@ namespace ICSharpCode.SharpDevelop @@ -20,8 +20,8 @@ namespace ICSharpCode.SharpDevelop
public static ScrollViewer GetScrollViewer(this DependencyObject o)
{
var scrollViewer = o as ScrollViewer;
if (scrollViewer != null) {
return scrollViewer;
if (scrollViewer != null) {
return scrollViewer;
}
for (int i = 0; i < VisualTreeHelper.GetChildrenCount(o); i++)
@ -60,5 +60,53 @@ namespace ICSharpCode.SharpDevelop @@ -60,5 +60,53 @@ namespace ICSharpCode.SharpDevelop
{
scrollViewer.ScrollToVerticalOffset(scrollViewer.VerticalOffset + offset);
}
public static void SynchronizeScroll(this ScrollViewer target, ScrollViewer source, ScrollSyncOption option)
{
double newScrollOffset;
switch (option) {
case ScrollSyncOption.Vertical:
newScrollOffset = source.VerticalOffset / source.ScrollableHeight * target.ScrollableHeight;
target.ScrollToVerticalOffset(double.IsNaN(newScrollOffset) ? 0 : newScrollOffset);
break;
case ScrollSyncOption.Horizontal:
newScrollOffset = source.HorizontalOffset / source.ScrollableWidth * target.ScrollableWidth;
target.ScrollToHorizontalOffset(double.IsNaN(newScrollOffset) ? 0 : newScrollOffset);
break;
case ScrollSyncOption.VerticalToHorizontal:
newScrollOffset = source.VerticalOffset / source.ScrollableHeight * target.ScrollableWidth;
target.ScrollToHorizontalOffset(double.IsNaN(newScrollOffset) ? 0 : newScrollOffset);
break;
case ScrollSyncOption.HorizontalToVertical:
newScrollOffset = source.HorizontalOffset / source.ScrollableWidth * target.ScrollableHeight;
target.ScrollToVerticalOffset(double.IsNaN(newScrollOffset) ? 0 : newScrollOffset);
break;
case ScrollSyncOption.Both:
newScrollOffset = source.VerticalOffset / source.ScrollableHeight * target.ScrollableHeight;
target.ScrollToVerticalOffset(double.IsNaN(newScrollOffset) ? 0 : newScrollOffset);
newScrollOffset = source.HorizontalOffset / source.ScrollableWidth * target.ScrollableWidth;
target.ScrollToHorizontalOffset(double.IsNaN(newScrollOffset) ? 0 : newScrollOffset);
break;
case ScrollSyncOption.BothInterchanged:
newScrollOffset = source.VerticalOffset / source.ScrollableHeight * target.ScrollableWidth;
target.ScrollToHorizontalOffset(double.IsNaN(newScrollOffset) ? 0 : newScrollOffset);
newScrollOffset = source.HorizontalOffset / source.ScrollableWidth * target.ScrollableHeight;
target.ScrollToVerticalOffset(double.IsNaN(newScrollOffset) ? 0 : newScrollOffset);
break;
default:
throw new Exception("Invalid value for ScrollSyncOption");
}
}
}
public enum ScrollSyncOption
{
Vertical,
Horizontal,
VerticalToHorizontal,
HorizontalToVertical,
Both,
BothInterchanged
}
}

Loading…
Cancel
Save