Browse Source

Merge trunk into dotnet4.

git-svn-id: svn://svn.sharpdevelop.net/sharpdevelop/branches/dotnet4@4303 1ccf3a8d-04fe-1044-b7c0-cef0b8235c61
shortcuts
Daniel Grunwald 16 years ago
parent
commit
e2973d98fe
  1. 6
      src/AddIns/BackendBindings/Python/PythonBinding/Test/Utils/MockProjectContent.cs
  2. 141
      src/AddIns/BackendBindings/XamlBinding/XamlBinding.Tests/UtilsTests.cs
  3. 3
      src/AddIns/BackendBindings/XamlBinding/XamlBinding.Tests/XamlBinding.Tests.csproj
  4. 4
      src/AddIns/BackendBindings/XamlBinding/XamlBinding.Tests/XmlTests.cs
  5. 403
      src/AddIns/BackendBindings/XamlBinding/XamlBinding/CompletionDataHelper.cs
  6. 30
      src/AddIns/BackendBindings/XamlBinding/XamlBinding/Extensions.cs
  7. 6
      src/AddIns/BackendBindings/XamlBinding/XamlBinding/MarkupExtensionInfo.cs
  8. 21
      src/AddIns/BackendBindings/XamlBinding/XamlBinding/MarkupExtensionParser.cs
  9. 2
      src/AddIns/BackendBindings/XamlBinding/XamlBinding/MarkupExtensionToken.cs
  10. 8
      src/AddIns/BackendBindings/XamlBinding/XamlBinding/MarkupExtensionTokenizer.cs
  11. 271
      src/AddIns/BackendBindings/XamlBinding/XamlBinding/Utils.cs
  12. 4
      src/AddIns/BackendBindings/XamlBinding/XamlBinding/XamlBinding.addin
  13. 1
      src/AddIns/BackendBindings/XamlBinding/XamlBinding/XamlBinding.csproj
  14. 127
      src/AddIns/BackendBindings/XamlBinding/XamlBinding/XamlCodeCompletionBinding.cs
  15. 16
      src/AddIns/BackendBindings/XamlBinding/XamlBinding/XamlColorizer.cs
  16. 91
      src/AddIns/BackendBindings/XamlBinding/XamlBinding/XamlCompletionItem.cs
  17. 31
      src/AddIns/BackendBindings/XamlBinding/XamlBinding/XamlCompletionItemList.cs
  18. 22
      src/AddIns/BackendBindings/XamlBinding/XamlBinding/XamlContext.cs
  19. 106
      src/AddIns/BackendBindings/XamlBinding/XamlBinding/XamlResolver.cs
  20. 36
      src/AddIns/DisplayBindings/AvalonEdit.AddIn/Src/CodeEditor.cs
  21. 18
      src/AddIns/DisplayBindings/AvalonEdit.AddIn/Src/CodeEditorAdapter.cs
  22. 45
      src/AddIns/DisplayBindings/AvalonEdit.AddIn/Src/SharpDevelopCompletionWindow.cs
  23. 10
      src/AddIns/DisplayBindings/XmlEditor/Project/Src/FormatXmlCommand.cs
  24. 60
      src/AddIns/DisplayBindings/XmlEditor/Project/Src/XmlCodeCompletionBinding.cs
  25. 4
      src/AddIns/DisplayBindings/XmlEditor/Project/Src/XmlCompletionDataProvider.cs
  26. 15
      src/AddIns/DisplayBindings/XmlEditor/Project/Src/XmlCompletionItem.cs
  27. 37
      src/AddIns/DisplayBindings/XmlEditor/Project/Src/XmlFormattingStrategy.cs
  28. 21
      src/AddIns/DisplayBindings/XmlEditor/Project/Src/XmlParser.cs
  29. 6
      src/AddIns/DisplayBindings/XmlEditor/Project/Src/XmlTreeView.cs
  30. 116
      src/AddIns/DisplayBindings/XmlEditor/Project/Src/XmlView.cs
  31. 5
      src/AddIns/DisplayBindings/XmlEditor/Project/XmlEditor.csproj
  32. 2
      src/AddIns/DisplayBindings/XmlEditor/Test/Parser/AttributeValueUnderCursorTests.cs
  33. 66
      src/AddIns/DisplayBindings/XmlEditor/XmlEditor.sln
  34. 19
      src/AddIns/Misc/Debugger/Debugger.AddIn/Project/Debugger.AddIn.csproj
  35. 1
      src/AddIns/Misc/Debugger/Debugger.AddIn/Project/Src/Visualizers/Graph/Drawing/NodeControl.xaml
  36. 103
      src/AddIns/Misc/Debugger/Debugger.AddIn/Project/Src/Visualizers/Graph/Drawing/NodeControl.xaml.cs
  37. 38
      src/AddIns/Misc/Debugger/Debugger.AddIn/Project/Src/Visualizers/Graph/ExpandedNodes.cs
  38. 2
      src/AddIns/Misc/Debugger/Debugger.AddIn/Project/Src/Visualizers/Graph/Layout/GraphMatcher.cs
  39. 2
      src/AddIns/Misc/Debugger/Debugger.AddIn/Project/Src/Visualizers/Graph/Layout/PositionedEdge.cs
  40. 7
      src/AddIns/Misc/Debugger/Debugger.AddIn/Project/Src/Visualizers/Graph/Layout/PositionedGraph.cs
  41. 79
      src/AddIns/Misc/Debugger/Debugger.AddIn/Project/Src/Visualizers/Graph/Layout/PositionedNode.cs
  42. 76
      src/AddIns/Misc/Debugger/Debugger.AddIn/Project/Src/Visualizers/Graph/Layout/PositionedNodeProperty.cs
  43. 25
      src/AddIns/Misc/Debugger/Debugger.AddIn/Project/Src/Visualizers/Graph/Layout/PositionedPropertyEventArgs.cs
  44. 44
      src/AddIns/Misc/Debugger/Debugger.AddIn/Project/Src/Visualizers/Graph/Layout/Tree/BoxDotFormatter.cs
  45. 70
      src/AddIns/Misc/Debugger/Debugger.AddIn/Project/Src/Visualizers/Graph/Layout/Tree/DotFormatter.cs
  46. 39
      src/AddIns/Misc/Debugger/Debugger.AddIn/Project/Src/Visualizers/Graph/Layout/Tree/NeatoDoubleFormatter.cs
  47. 13
      src/AddIns/Misc/Debugger/Debugger.AddIn/Project/Src/Visualizers/Graph/Layout/Tree/NeatoEdgeRouter.cs
  48. 6
      src/AddIns/Misc/Debugger/Debugger.AddIn/Project/Src/Visualizers/Graph/Layout/Tree/NeatoProcess.cs
  49. 68
      src/AddIns/Misc/Debugger/Debugger.AddIn/Project/Src/Visualizers/Graph/Layout/Tree/RecordDotFormatter.cs
  50. 8
      src/AddIns/Misc/Debugger/Debugger.AddIn/Project/Src/Visualizers/Graph/Layout/Tree/TreeEdge.cs
  51. 36
      src/AddIns/Misc/Debugger/Debugger.AddIn/Project/Src/Visualizers/Graph/Layout/Tree/TreeLayouter.cs
  52. 40
      src/AddIns/Misc/Debugger/Debugger.AddIn/Project/Src/Visualizers/Graph/Layout/Tree/TreeNode.cs
  53. 2
      src/AddIns/Misc/Debugger/Debugger.AddIn/Project/Src/Visualizers/Graph/Layout/Tree/TreeNodeLR.cs
  54. 2
      src/AddIns/Misc/Debugger/Debugger.AddIn/Project/Src/Visualizers/Graph/Layout/Tree/TreeNodeTB.cs
  55. 4
      src/AddIns/Misc/Debugger/Debugger.AddIn/Project/Src/Visualizers/Graph/ObjectGraph/NamedEdge.cs
  56. 3
      src/AddIns/Misc/Debugger/Debugger.AddIn/Project/Src/Visualizers/Graph/ObjectGraph/ObjectGraph.cs
  57. 109
      src/AddIns/Misc/Debugger/Debugger.AddIn/Project/Src/Visualizers/Graph/ObjectGraph/ObjectGraphBuilder.cs
  58. 34
      src/AddIns/Misc/Debugger/Debugger.AddIn/Project/Src/Visualizers/Graph/ObjectGraph/ObjectNode.cs
  59. 13
      src/AddIns/Misc/Debugger/Debugger.AddIn/Project/Src/Visualizers/Graph/ObjectGraph/ObjectProperty.cs
  60. 39
      src/AddIns/Misc/Debugger/Debugger.AddIn/Project/Src/Visualizers/Graph/ObjectGraphVisualizerViewContent.cs
  61. 12
      src/AddIns/Misc/Debugger/Debugger.AddIn/Project/Src/Visualizers/Graph/VisualizerWPFControl.xaml
  62. 33
      src/AddIns/Misc/Debugger/Debugger.AddIn/Project/Src/Visualizers/Graph/VisualizerWPFControl.xaml.cs
  63. 71
      src/AddIns/Misc/Debugger/Debugger.AddIn/Project/Src/Visualizers/Graph/VisualizerWPFWindow.xaml.cs
  64. 92
      src/AddIns/Misc/Debugger/Debugger.AddIn/Project/Src/Visualizers/Graph/VisualizerWinFormsControl.Designer.cs
  65. 84
      src/AddIns/Misc/Debugger/Debugger.AddIn/Project/Src/Visualizers/Graph/VisualizerWinFormsControl.cs
  66. 4
      src/AddIns/Misc/Debugger/Debugger.Tests/Project/Src/TestPrograms/MemoryReadWrite.cs
  67. 6
      src/AddIns/Misc/UnitTesting/Test/Utils/MockProjectContent.cs
  68. 1
      src/Libraries/AvalonDock/AvalonDock.csproj
  69. 25
      src/Libraries/AvalonDock/DeserializationCallbackEventArgs.cs
  70. 8
      src/Libraries/AvalonDock/DockableContent.cs
  71. 6
      src/Libraries/AvalonDock/DockablePane.cs
  72. 130
      src/Libraries/AvalonDock/DockingManager.cs
  73. 24
      src/Libraries/AvalonDock/FloatingWindow.cs
  74. 2
      src/Libraries/AvalonDock/Properties/AssemblyInfo.cs
  75. 2
      src/Libraries/AvalonDock/ResizingPanel.cs
  76. 6
      src/Libraries/AvalonEdit/ICSharpCode.AvalonEdit/CodeCompletion/CompletionList.cs
  77. 32
      src/Libraries/AvalonEdit/ICSharpCode.AvalonEdit/CodeCompletion/CompletionWindow.cs
  78. 8
      src/Libraries/AvalonEdit/ICSharpCode.AvalonEdit/CodeCompletion/CompletionWindowBase.cs
  79. 5
      src/Libraries/AvalonEdit/ICSharpCode.AvalonEdit/CodeCompletion/InsightWindow.cs
  80. 2
      src/Libraries/AvalonEdit/ICSharpCode.AvalonEdit/Document/NewLineFinder.cs
  81. 2
      src/Libraries/AvalonEdit/ICSharpCode.AvalonEdit/Editing/EditingCommandHandler.cs
  82. 2
      src/Main/Base/Project/ICSharpCode.SharpDevelop.csproj
  83. 24
      src/Main/Base/Project/Src/Editor/AvalonEdit/AvalonEditTextEditorAdapter.cs
  84. 24
      src/Main/Base/Project/Src/Editor/CodeCompletion/ICompletionListWindow.cs
  85. 62
      src/Main/Base/Project/Src/Editor/CodeCompletion/ICompletionWindow.cs
  86. 30
      src/Main/Base/Project/Src/Editor/CodeCompletion/IInsightWindow.cs
  87. 7
      src/Main/Base/Project/Src/Editor/ITextEditor.cs
  88. 2
      src/Main/Base/Project/Src/Gui/Dialogs/NewFileDialog.cs
  89. 2
      src/Main/Base/Project/Src/Gui/Pads/TaskList/TaskView.cs
  90. 7
      src/Main/Base/Project/Src/Services/ParserService/ParseProjectContent.cs
  91. 9
      src/Main/Base/Project/Src/TextEditor/Gui/TextEditorAdapter.cs
  92. 7
      src/Main/ICSharpCode.SharpDevelop.Dom/Project/Src/ProjectContent/DefaultProjectContent.cs
  93. 7
      src/Main/ICSharpCode.SharpDevelop.Dom/Project/Src/ProjectContent/IProjectContent.cs
  94. 6
      src/Main/ICSharpCode.SharpDevelop.Dom/Project/Src/ProjectContent/ReflectionProjectContent.cs

6
src/AddIns/BackendBindings/Python/PythonBinding/Test/Utils/MockProjectContent.cs

@ -354,5 +354,11 @@ namespace PythonBinding.Tests.Utils @@ -354,5 +354,11 @@ namespace PythonBinding.Tests.Utils
{
throw new NotImplementedException();
}
public string AssemblyName {
get {
throw new NotImplementedException();
}
}
}
}

141
src/AddIns/BackendBindings/XamlBinding/XamlBinding.Tests/UtilsTests.cs

@ -18,85 +18,134 @@ namespace ICSharpCode.XamlBinding.Tests @@ -18,85 +18,134 @@ namespace ICSharpCode.XamlBinding.Tests
public class UtilsTests
{
[Test]
public void XmlNamespacesForOffsetSimple()
public void DiffTestSimple()
{
string xaml = File.ReadAllText("Test1.xaml");
int offset = xaml.IndexOf("CheckBox") + "CheckBox ".Length;
string xaml = "<Test val1=\"Test\" />";
int offset = "<Test val1=\"Te".Length;
int expectedResult = offset - "<Test val1=\"".Length;
var expectedResult = new Dictionary<string, string> {
{"xmlns", "http://schemas.microsoft.com/netfx/2007/xaml/presentation"},
{"xmlns:x", "http://schemas.microsoft.com/winfx/2006/xaml"}
};
int actualResult = Utils.GetOffsetFromValueStart(xaml, offset);
var result = Utils.GetXmlNamespacesForOffset(xaml, offset);
Assert.AreEqual(expectedResult, actualResult);
}
[Test]
public void DiffTestSimple2()
{
string xaml = "<Test val1=\"Test\" />";
int offset = "<Test val1=\"".Length;
int expectedResult = offset - "<Test val1=\"".Length;
foreach (var p in result)
Debug.Print(p.Key + " " + p.Value);
int actualResult = Utils.GetOffsetFromValueStart(xaml, offset);
Assert.AreEqual(expectedResult, result, "Is not equal");
Assert.AreEqual(expectedResult, actualResult);
}
[Test]
public void XmlNamespacesForOffsetSimple2()
public void GetOffsetTest1()
{
string xaml = File.ReadAllText("Test2.xaml");
int offset = xaml.IndexOf("CheckBox") + "CheckBox ".Length;
string text = @"SharpDevelop uses the MSBuild
libraries for compilation. But when you compile a project
inside SharpDevelop, there's more going on than a
simple call to MSBuild.";
int expected = 0;
int line = 1;
int col = 1;
var expectedResult = new Dictionary<string, string> {
{"xmlns", "http://schemas.microsoft.com/netfx/2007/xaml/presentation"},
{"xmlns:x", "http://schemas.microsoft.com/winfx/2006/xaml"},
{"xmlns:y", "clr-namespace:ICSharpCode.Profiler.Controls;assembly=ICSharpCode.Profiler.Controls"}
};
int result = Utils.GetOffsetFromFilePos(text, line, col);
Assert.AreEqual(expected, result);
}
[Test]
public void GetOffsetTest2()
{
string text = @"SharpDevelop uses the MSBuild
libraries for compilation. But when you compile a project
inside SharpDevelop, there's more going on than a
simple call to MSBuild.";
var result = Utils.GetXmlNamespacesForOffset(xaml, offset);
int expected = 4;
int line = 1;
int col = 5;
foreach (var p in result)
Debug.Print(p.Key + " " + p.Value);
int result = Utils.GetOffsetFromFilePos(text, line, col);
Assert.AreEqual(expectedResult, result, "Is not equal");
Assert.AreEqual(expected, result);
}
[Test]
public void XmlNamespacesForOffsetComplex()
public void GetOffsetTest3()
{
string xaml = File.ReadAllText("Test3.xaml");
int offset = xaml.IndexOf("CheckBox") + "CheckBox ".Length;
string text = @"SharpDevelop uses the MSBuild
libraries for compilation. But when you compile a project
inside SharpDevelop, there's more going on than a
simple call to MSBuild.";
var expectedResult = new Dictionary<string, string> {
{"xmlns", "http://schemas.microsoft.com/netfx/2007/xaml/presentation"},
{"xmlns:x", "clr-namespace:ICSharpCode.Profiler.Controls;assembly=ICSharpCode.Profiler.Controls"}
};
int expected = 0;
int line = 0;
int col = 5;
var result = Utils.GetXmlNamespacesForOffset(xaml, offset);
int result = Utils.GetOffsetFromFilePos(text, line, col);
foreach (var p in result)
Debug.Print(p.Key + " " + p.Value);
Assert.AreEqual(expected, result);
}
[Test]
public void GetOffsetTest4()
{
string text = @"SharpDevelop uses the MSBuild
libraries for compilation. But when you compile a project
inside SharpDevelop, there's more going on than a
simple call to MSBuild.";
int expected = @"SharpDevelop uses the MSBuild
libraries".Length - 1;
int line = 2;
int col = 10;
int result = Utils.GetOffsetFromFilePos(text, line, col);
Assert.AreEqual(expectedResult, result, "Is not equal");
Assert.AreEqual(expected, result);
}
[Test]
public void DiffTestSimple()
public void GetOffsetTest5()
{
string xaml = "<Test val1=\"Test\" />";
int offset = "<Test val1=\"Te".Length;
int expectedResult = offset - "<Test val1=\"".Length;
string text = @"SharpDevelop uses the MSBuild
libraries for compilation. But when you compile a project
inside SharpDevelop, there's more going on than a
simple call to MSBuild.";
int actualResult = Utils.GetOffsetFromValueStart(xaml, offset);
int expected = text.Length;
int line = 10;
int col = 10;
Assert.AreEqual(expectedResult, actualResult);
int result = Utils.GetOffsetFromFilePos(text, line, col);
Assert.AreEqual(expected, result);
}
[Test]
public void DiffTestSimple2()
public void GetOffsetTest6()
{
string xaml = "<Test val1=\"Test\" />";
int offset = "<Test val1=\"".Length;
int expectedResult = offset - "<Test val1=\"".Length;
string text = @"SharpDevelop uses the MSBuild
libraries for compilation. But when you compile a project
inside SharpDevelop, there's more going on than a
simple call to MSBuild.";
int actualResult = Utils.GetOffsetFromValueStart(xaml, offset);
int expected = @"SharpDevelop uses the MSBuild
libraries for compilation. But when you compile a project
inside SharpDevelop, there's more going on than a
simple".Length - 1;
Assert.AreEqual(expectedResult, actualResult);
int line = 4;
int col = 7;
int result = Utils.GetOffsetFromFilePos(text, line, col);
Assert.AreEqual(expected, result);
}
}
}

3
src/AddIns/BackendBindings/XamlBinding/XamlBinding.Tests/XamlBinding.Tests.csproj

@ -38,8 +38,7 @@ @@ -38,8 +38,7 @@
<Import Project="$(MSBuildBinPath)\Microsoft.CSharp.Targets" />
<ItemGroup>
<Reference Include="nunit.framework">
<HintPath>..\..\..\..\Tools\NUnit\nunit.framework.dll</HintPath>
<Private>False</Private>
<HintPath>..\..\..\..\..\bin\Tools\NUnit\nunit.framework.dll</HintPath>
</Reference>
<Reference Include="System" />
<Reference Include="System.Core">

4
src/AddIns/BackendBindings/XamlBinding/XamlBinding.Tests/XmlTests.cs

@ -66,6 +66,8 @@ namespace ICSharpCode.XamlBinding.Tests @@ -66,6 +66,8 @@ namespace ICSharpCode.XamlBinding.Tests
int offset = "<Test val1=\"{Bin".Length;
Assert.AreEqual(true, XmlParser.IsInsideAttributeValue(xaml, offset));
Assert.AreEqual("{Binding Value}", XmlParser.GetAttributeValueAtIndex(xaml, offset));
Assert.AreEqual("val1", XmlParser.GetAttributeNameAtIndex(xaml, offset));
}
[Test]
@ -75,6 +77,8 @@ namespace ICSharpCode.XamlBinding.Tests @@ -75,6 +77,8 @@ namespace ICSharpCode.XamlBinding.Tests
int offset = "<Test val1=\"{Binding Value, Path=".Length;
Assert.AreEqual(true, XmlParser.IsInsideAttributeValue(xaml, offset));
Assert.AreEqual("{Binding Value, Path=Control}", XmlParser.GetAttributeValueAtIndex(xaml, offset));
Assert.AreEqual("val1", XmlParser.GetAttributeNameAtIndex(xaml, offset));
}
}
}

403
src/AddIns/BackendBindings/XamlBinding/XamlBinding/CompletionDataHelper.cs

@ -5,7 +5,7 @@ @@ -5,7 +5,7 @@
// <version>$Revision$</version>
// </file>
using ICSharpCode.SharpDevelop.Editor.CodeCompletion;
using ICSharpCode.SharpDevelop.Project;
using System;
using System.Collections.Generic;
using System.Diagnostics;
@ -15,6 +15,7 @@ using System.Xml; @@ -15,6 +15,7 @@ using System.Xml;
using ICSharpCode.SharpDevelop;
using ICSharpCode.SharpDevelop.Dom;
using ICSharpCode.SharpDevelop.Editor;
using ICSharpCode.SharpDevelop.Editor.CodeCompletion;
using ICSharpCode.XmlEditor;
using LoggingService = ICSharpCode.Core.LoggingService;
@ -32,37 +33,93 @@ namespace ICSharpCode.XamlBinding @@ -32,37 +33,93 @@ namespace ICSharpCode.XamlBinding
static readonly List<ICompletionItem> standardAttributes = new List<ICompletionItem> {
new DefaultCompletionItem("xmlns:")
};
static readonly List<string> xamlNamespaceAttributes = new List<string> {
"Class", "ClassModifier", "FieldModifier", "Name", "Subclass", "TypeArguments", "Uid"
};
#endregion
public const string XamlNamespace = "http://schemas.microsoft.com/winfx/2006/xaml";
public static XamlContext ResolveContext(ITextEditor editor, char typedValue)
public static XamlContext ResolveContext(string text, string fileName, int line, int col)
{
string text = editor.Document.Text;
int offset = editor.Caret.Offset;
XamlResolver resolver = new XamlResolver();
int offset = Utils.GetOffsetFromFilePos(text, line, col);
ParseInformation info = ParserService.GetParseInformation(editor.FileName);
ParseInformation info = ParserService.GetParseInformation(fileName);
XmlElementPath path = XmlParser.GetActiveElementStartPathAtIndex(text, offset);
string attribute = XmlParser.GetAttributeNameAtIndex(text, offset);
string attributeValue = XmlParser.GetAttributeValueAtIndex(text, offset);
bool inAttributeValue = XmlParser.IsInsideAttributeValue(text, offset);
int offsetFromValueStart = Utils.GetOffsetFromValueStart(text, offset);
ResolveResult rr = null;
AttributeValue value = null;
XamlExpressionContext cxt = new XamlExpressionContext(path, attribute, inAttributeValue);
value = MarkupExtensionParser.ParseValue(attributeValue);
XamlContextDescription description = XamlContextDescription.InTag;
if (path == null || path.Elements.Count == 0) {
description = XamlContextDescription.None;
path = XmlParser.GetParentElementPath(text.Substring(0, offset));
} else {
int ltOffset = XmlParser.GetActiveElementStartIndex(text, offset);
if (ltOffset == -1)
description = XamlContextDescription.AtTag;
else {
string space = text.Substring(ltOffset + 1, offset - ltOffset - 1);
var last = path.Elements.LastOrDefault();
if (last != null && last.ToString().StartsWith(space, StringComparison.Ordinal))
description = XamlContextDescription.AtTag;
}
}
if (inAttributeValue)
description = XamlContextDescription.InAttributeValue;
if (value != null && !value.IsString)
description = XamlContextDescription.InMarkupExtension;
if (Utils.IsInsideXmlComment(text, offset))
description = XamlContextDescription.InComment;
Dictionary<string, string> xmlnsDefs = new Dictionary<string, string>();
using (XmlTextReader reader = Utils.CreateReaderAtTarget(text, line, col)) {
xmlnsDefs.AddRange(reader.GetNamespacesInScope(XmlNamespaceScope.All));
}
var context = new XamlContext() {
Description = description,
AttributeName = attribute,
AttributeValue = value,
RawAttributeValue = attributeValue,
ValueStartOffset = offsetFromValueStart,
Path = (path == null || path.Elements.Count == 0) ? null : path,
XmlnsDefinitions = xmlnsDefs,
ParseInformation = info
};
if (!string.IsNullOrEmpty(attribute)) {
rr = resolver.Resolve(new ExpressionResult(attribute, cxt) { Region = new DomRegion(1,1) }, info, text);
return context;
}
public static XamlCompletionContext ResolveCompletionContext(ITextEditor editor, char typedValue)
{
string text = editor.Document.Text;
int offset = editor.Caret.Offset;
ParseInformation info = ParserService.GetParseInformation(editor.FileName);
XmlElementPath path = XmlParser.GetActiveElementStartPathAtIndex(text, offset);
string attribute = XmlParser.GetAttributeNameAtIndex(text, offset);
string attributeValue = XmlParser.GetAttributeValueAtIndex(text, offset);
bool inAttributeValue = XmlParser.IsInsideAttributeValue(text, offset);
int offsetFromValueStart = Utils.GetOffsetFromValueStart(text, offset);
AttributeValue value = null;
value = MarkupExtensionParser.ParseValue(attributeValue);
XamlContextDescription description = XamlContextDescription.InTag;
if (path == null || path.Elements.Count == 0) {
description = XamlContextDescription.AtTag;
description = XamlContextDescription.None;
path = XmlParser.GetParentElementPath(text.Substring(0, offset));
} else {
int ltOffset = XmlParser.GetActiveElementStartIndex(text, offset);
@ -71,7 +128,7 @@ namespace ICSharpCode.XamlBinding @@ -71,7 +128,7 @@ namespace ICSharpCode.XamlBinding
else {
string space = text.Substring(ltOffset + 1, offset - ltOffset - 1);
var last = path.Elements.LastOrDefault();
if (last != null && last.ToString().Equals(space, StringComparison.Ordinal))
if (last != null && last.ToString().StartsWith(space, StringComparison.Ordinal))
description = XamlContextDescription.AtTag;
}
}
@ -85,47 +142,116 @@ namespace ICSharpCode.XamlBinding @@ -85,47 +142,116 @@ namespace ICSharpCode.XamlBinding
if (Utils.IsInsideXmlComment(text, offset))
description = XamlContextDescription.InComment;
var context = new XamlContext() {
Dictionary<string, string> xmlnsDefs = new Dictionary<string, string>();
using (XmlTextReader reader = Utils.CreateReaderAtTarget(text, editor.Caret.Line, editor.Caret.Column)) {
xmlnsDefs.AddRange(reader.GetNamespacesInScope(XmlNamespaceScope.All));
}
var context = new XamlCompletionContext() {
PressedKey = typedValue,
Description = description,
ResolvedExpression = rr,
AttributeName = attribute,
AttributeValue = value,
RawAttributeValue = attributeValue,
ValueStartOffset = offsetFromValueStart,
Path = (path == null || path.Elements.Count == 0) ? null : path
Path = (path == null || path.Elements.Count == 0) ? null : path,
XmlnsDefinitions = xmlnsDefs,
ParseInformation = info,
Editor = editor
};
LoggingService.Debug(context);
return context;
}
static List<ICompletionItem> CreateListForAttributeName(ParseInformation parseInfo, XamlExpressionContext context, string[] existingItems)
static List<ICompletionItem> CreateListForAttributeName(XamlCompletionContext context, string[] existingItems)
{
if (context.ElementPath.Elements.Count == 0)
return null;
QualifiedName lastElement = context.ElementPath.Elements[context.ElementPath.Elements.Count - 1];
XamlCompilationUnit cu = parseInfo.BestCompilationUnit as XamlCompilationUnit;
QualifiedName lastElement = context.Path.Elements.LastOrDefault();
XamlCompilationUnit cu = context.ParseInformation.BestCompilationUnit as XamlCompilationUnit;
if (cu == null)
return null;
IReturnType rt = cu.CreateType(lastElement.Namespace, lastElement.Name);
IReturnType rt = cu.CreateType(lastElement.Namespace, lastElement.Name.Trim('.'));
if (rt == null)
return null;
var list = new List<ICompletionItem>();
string xamlPrefix = Utils.GetXamlNamespacePrefix(context);
foreach (string item in xamlNamespaceAttributes) {
if (!existingItems.Contains(xamlPrefix + ":" + item))
list.Add(new XamlCompletionItem(xamlPrefix, XamlNamespace, item));
}
foreach (IProperty p in rt.GetProperties()) {
if (p.IsPublic && p.CanSet && !existingItems.Contains(p.Name)) {
list.Add(new XamlCompletionItem(p));
list.Add(new XamlCodeCompletionItem(p));
}
}
foreach (IEvent e in rt.GetEvents()) {
if (e.IsPublic && !existingItems.Contains(e.Name)) {
list.Add(new XamlCompletionItem(e));
list.Add(new XamlCodeCompletionItem(e));
}
}
return list;
}
public static IEnumerable<ICompletionItem> CreateListForXmlnsCompletion(IProjectContent projectContent)
{
List<XmlnsCompletionItem> list = new List<XmlnsCompletionItem>();
foreach (IProjectContent content in projectContent.ReferencedContents) {
foreach (IAttribute att in content.GetAssemblyAttributes()) {
if (att.PositionalArguments.Count == 2
&& att.AttributeType.FullyQualifiedName == "System.Windows.Markup.XmlnsDefinitionAttribute") {
list.Add(new XmlnsCompletionItem(att.PositionalArguments[0] as string, true));
}
}
foreach (string @namespace in content.NamespaceNames) {
if (!string.IsNullOrEmpty(@namespace))
list.Add(new XmlnsCompletionItem(@namespace, content.AssemblyName));
}
}
foreach (string @namespace in projectContent.NamespaceNames) {
if (!string.IsNullOrEmpty(@namespace))
list.Add(new XmlnsCompletionItem(@namespace, false));
}
return list
.Distinct(new XmlnsEqualityComparer())
.OrderBy(item => item, new XmlnsComparer())
.Cast<ICompletionItem>();
}
sealed class XmlnsEqualityComparer : IEqualityComparer<XmlnsCompletionItem> {
public bool Equals(XmlnsCompletionItem x, XmlnsCompletionItem y)
{
return x.Namespace == y.Namespace && x.Assembly == y.Assembly;
}
public int GetHashCode(XmlnsCompletionItem obj)
{
return string.IsNullOrEmpty(obj.Assembly) ? obj.Namespace.GetHashCode() : obj.Namespace.GetHashCode() ^ obj.Assembly.GetHashCode();
}
}
sealed class XmlnsComparer : IComparer<XmlnsCompletionItem> {
public int Compare(XmlnsCompletionItem x, XmlnsCompletionItem y)
{
if (x.IsUrl && y.IsUrl)
return x.Namespace.CompareTo(y.Namespace);
if (x.IsUrl)
return -1;
if (y.IsUrl)
return 1;
if (x.Assembly == y.Assembly)
return x.Namespace.CompareTo(y.Namespace);
else
return x.Assembly.CompareTo(y.Assembly);
}
}
static bool IsReaderAtTarget(XmlTextReader r, int caretLine, int caretColumn)
{
if (r.LineNumber > caretLine)
@ -136,18 +262,18 @@ namespace ICSharpCode.XamlBinding @@ -136,18 +262,18 @@ namespace ICSharpCode.XamlBinding
return false;
}
public static IList<ICompletionItem> CreateListForElement(ParseInformation parseInfo, string fileContent, int caretLine, int caretColumn)
public static IList<ICompletionItem> CreateListForElement(ParseInformation parseInfo, string fileContent, int caretLine, int caretColumn, bool addOpeningBrace)
{
var items = GetClassesFromContext(parseInfo, fileContent, caretLine, caretColumn);
var result = new List<ICompletionItem>();
foreach (var ns in items) {
result.AddRange(from c in ns.Value
result.AddRange((from c in ns.Value
where (c.ClassType == ClassType.Class &&
!c.IsAbstract && !c.IsStatic &&
!c.ClassInheritanceTree.Any(b => b.FullyQualifiedName == "System.Attribute") &&
c.Methods.Any(m => m.IsConstructor && m.IsPublic))
select (new XamlCompletionItem(c, ns.Key) as ICompletionItem)
select (new XamlCodeCompletionItem(c, ns.Key, addOpeningBrace))).Cast<ICompletionItem>()
);
}
@ -156,48 +282,61 @@ namespace ICSharpCode.XamlBinding @@ -156,48 +282,61 @@ namespace ICSharpCode.XamlBinding
public static IList<ICompletionItem> CreateListOfMarkupExtensions(ParseInformation parseInfo, string fileContent, int caretLine, int caretColumn)
{
var list = CreateListForElement(parseInfo, fileContent, caretLine, caretColumn);
var list = CreateListForElement(parseInfo, fileContent, caretLine, caretColumn, false);
var neededItems = list
.Where(i => ((i as XamlCompletionItem).Entity as IClass).ClassInheritanceTree
.Where(i => ((i as XamlCodeCompletionItem).Entity as IClass).ClassInheritanceTree
.Any(item => item.FullyQualifiedName == "System.Windows.Markup.MarkupExtension"))
.Select(
selItem => {
var it = selItem as XamlCompletionItem;
var it = selItem as XamlCodeCompletionItem;
string text = it.Text;
if (it.Text.EndsWith("Extension", StringComparison.Ordinal))
text = text.Remove(it.Text.Length - "Extension".Length);
return new XamlCompletionItem(text, it.Entity) as ICompletionItem;
return new XamlCodeCompletionItem(it.Entity, text);
}
);
)
.Cast<ICompletionItem>();
return neededItems.ToList();
}
public static ICompletionItemList CreateListForContext(ITextEditor editor, XamlContext context)
public static ICompletionItemList CreateListForContext(ITextEditor editor, XamlCompletionContext context)
{
XamlCompletionItemList list = new XamlCompletionItemList();
ParseInformation info = ParserService.GetParseInformation(editor.FileName);
switch (context.Description) {
case XamlContextDescription.None:
if (context.Forced) {
list.Items.AddRange(standardElements.Select(item => new DefaultCompletionItem("<" + item.Text)).Cast<ICompletionItem>());
list.Items.AddRange(CreateListForElement(info, editor.Document.Text, editor.Caret.Line, editor.Caret.Column, true));
}
break;
case XamlContextDescription.AtTag:
list.Items.AddRange(standardElements);
list.Items.AddRange(CreateListForElement(info, editor.Document.Text, editor.Caret.Line, editor.Caret.Column));
if (editor.Document.GetCharAt(editor.Caret.Offset - 1) == '.' || context.PressedKey == '.') {
var loc = editor.Document.OffsetToPosition(Utils.GetParentElementStart(editor));
var existing = Utils.GetListOfExistingAttributeNames(editor.Document.Text, loc.Line, loc.Column);
list.Items.AddRange(CreateListForAttributeName(context, existing).RemoveEvents());
} else
list.Items.AddRange(CreateListForElement(info, editor.Document.Text, editor.Caret.Line, editor.Caret.Column, false));
break;
case XamlContextDescription.InTag:
var existing = Utils.GetListOfExistingAttributeNames(editor.Document.Text, editor.Caret.Offset);
list.Items.AddRange(CreateListForAttributeName(info, new XamlExpressionContext(context.Path, null, false), existing));
var existingAttribs = Utils.GetListOfExistingAttributeNames(editor.Document.Text, editor.Caret.Line, editor.Caret.Column);
list.Items.AddRange(CreateListForAttributeName(context, existingAttribs));
QualifiedName last = context.Path.Elements[context.Path.Elements.Count - 1];
TypeResolveResult trr = new XamlResolver().Resolve(new ExpressionResult(last.Name, new XamlExpressionContext(context.Path, null, false)), info, editor.Document.Text) as TypeResolveResult;
TypeResolveResult trr = new XamlResolver().Resolve(new ExpressionResult(last.Name, context), info, editor.Document.Text) as TypeResolveResult;
if (trr != null && trr.ResolvedType != null && trr.ResolvedType.GetUnderlyingClass() != null) {
if (trr.ResolvedType.GetUnderlyingClass().ClassInheritanceTree.Any(i => i.FullyQualifiedName == "System.Windows.DependencyObject")) {
list.Items.AddRange(GetListOfAttachedProperties(info, editor.Document.Text, editor.Caret.Line, editor.Caret.Column, existing));
list.Items.AddRange(GetListOfAttachedEvents(info, editor.Document.Text, editor.Caret.Line, editor.Caret.Column, existing));
list.Items.AddRange(GetListOfAttachedProperties(info, editor.Document.Text, editor.Caret.Line, editor.Caret.Column, existingAttribs));
list.Items.AddRange(GetListOfAttachedEvents(info, editor.Document.Text, editor.Caret.Line, editor.Caret.Column, existingAttribs));
}
}
list.Items.AddRange(standardAttributes);
break;
case XamlContextDescription.InAttributeValue:
@ -210,10 +349,24 @@ namespace ICSharpCode.XamlBinding @@ -210,10 +349,24 @@ namespace ICSharpCode.XamlBinding
return list;
}
public static IEnumerable<IInsightItem> CreateMarkupExtensionInsight(XamlContext context, ParseInformation info, ITextEditor editor)
static bool FilterCollectionAttributes(ICompletionItem item)
{
if (item is XamlCodeCompletionItem) {
var comItem = item as XamlCodeCompletionItem;
if (comItem.Entity is IProperty) {
var prop = comItem.Entity as IProperty;
var c = prop.ReturnType.GetUnderlyingClass();
return c != null && c.ClassInheritanceTree.Any(b => b.FullyQualifiedName == "System.Collections.IEnumerable");
}
}
return false;
}
public static IEnumerable<IInsightItem> CreateMarkupExtensionInsight(XamlCompletionContext context, ParseInformation info, ITextEditor editor)
{
var markup = GetInnermostMarkup(context.AttributeValue.ExtensionValue);
var trr = ResolveMarkupExtensionType(markup, info, editor, context.Path);
var markup = Utils.GetInnermostMarkup(context.AttributeValue.ExtensionValue);
var trr = ResolveMarkupExtensionType(markup, context);
if (trr != null) {
var ctors = trr.ResolvedType
@ -228,14 +381,14 @@ namespace ICSharpCode.XamlBinding @@ -228,14 +381,14 @@ namespace ICSharpCode.XamlBinding
}
}
public static ICompletionItemList CreateMarkupExtensionCompletion(XamlContext context, ParseInformation info, ITextEditor editor)
public static ICompletionItemList CreateMarkupExtensionCompletion(XamlCompletionContext context, ParseInformation info, ITextEditor editor)
{
var list = new XamlCompletionItemList();
var path = XmlParser.GetActiveElementStartPathAtIndex(editor.Document.Text, editor.Caret.Offset);
var markup = GetInnermostMarkup(context.AttributeValue.ExtensionValue);
var markup = Utils.GetInnermostMarkup(context.AttributeValue.ExtensionValue);
var trr = ResolveMarkupExtensionType(markup, info, editor, path);
var trr = ResolveMarkupExtensionType(markup, context);
if (trr == null) {
list.Items.AddRange(CreateListOfMarkupExtensions(info, editor.Document.Text, editor.Caret.Line, editor.Caret.Column));
@ -259,11 +412,11 @@ namespace ICSharpCode.XamlBinding @@ -259,11 +412,11 @@ namespace ICSharpCode.XamlBinding
{
var ctors = trr.ResolvedType.GetMethods().Where(m => m.IsConstructor && m.Parameters.Count >= markup.PositionalArguments.Count);
if (ctors.Any(ctor => ctor.Parameters.Count >= markup.PositionalArguments.Count)) {
list.Items.AddRange(trr.ResolvedType.GetProperties().Select(p => new XamlCompletionItem(p.Name + "=", p) as ICompletionItem));
list.Items.AddRange(trr.ResolvedType.GetProperties().Where(p => p.CanSet && p.IsPublic).Select(p => new XamlCodeCompletionItem(p, p.Name + "=")).Cast<ICompletionItem>());
}
}
static void DoPositionalArgsCompletion(XamlCompletionItemList list, XamlContext context, TypeResolveResult trr, ParseInformation info, ITextEditor editor)
static void DoPositionalArgsCompletion(XamlCompletionItemList list, XamlCompletionContext context, TypeResolveResult trr, ParseInformation info, ITextEditor editor)
{
switch (trr.ResolvedType.FullyQualifiedName) {
case "System.Windows.Markup.ArrayExtension":
@ -272,12 +425,12 @@ namespace ICSharpCode.XamlBinding @@ -272,12 +425,12 @@ namespace ICSharpCode.XamlBinding
break;
case "System.Windows.Markup.StaticExtension":
if (context.AttributeValue.ExtensionValue.PositionalArguments.Count == 1 && context.PressedKey == ' ') break;
if (context.AttributeValue.ExtensionValue.PositionalArguments.Count <= 1) DoStaticExtensionCompletion(list, context, info, editor);
if (context.AttributeValue.ExtensionValue.PositionalArguments.Count <= 1) DoStaticExtensionCompletion(list, context);
break;
case "System.Windows.Markup.TypeExtension":
if (context.AttributeValue.ExtensionValue.PositionalArguments.Count == 1 && context.PressedKey == ' ') break;
if (context.AttributeValue.ExtensionValue.PositionalArguments.Count <= 1) {
list.Items.AddRange(CreateListForElement(info, editor.Document.Text, editor.Caret.Line, editor.Caret.Column));
list.Items.AddRange(CreateListForElement(info, editor.Document.Text, editor.Caret.Line, editor.Caret.Column, false));
AttributeValue selItem = context.AttributeValue.ExtensionValue.PositionalArguments.LastOrDefault();
if (selItem != null && selItem.IsString) {
string s = selItem.StringValue;
@ -318,7 +471,7 @@ namespace ICSharpCode.XamlBinding @@ -318,7 +471,7 @@ namespace ICSharpCode.XamlBinding
}
}
public static IEnumerable<ICompletionItem> MemberCompletion(ITextEditor editor, IReturnType type)
public static IEnumerable<ICompletionItem> MemberCompletion(XamlCompletionContext context, IReturnType type)
{
if (type == null || type.GetUnderlyingClass() == null)
yield break;
@ -328,7 +481,7 @@ namespace ICSharpCode.XamlBinding @@ -328,7 +481,7 @@ namespace ICSharpCode.XamlBinding
switch (c.ClassType) {
case ClassType.Enum:
foreach (IField f in c.Fields)
yield return new XamlCompletionItem(f);
yield return new XamlCodeCompletionItem(f);
break;
case ClassType.Struct:
if (c.FullyQualifiedName == "System.Boolean") {
@ -339,60 +492,79 @@ namespace ICSharpCode.XamlBinding @@ -339,60 +492,79 @@ namespace ICSharpCode.XamlBinding
case ClassType.Delegate:
IMethod invoker = c.Methods.Where(method => method.Name == "Invoke").FirstOrDefault();
if (invoker != null) {
var path = XmlParser.GetActiveElementStartPathAtIndex(editor.Document.Text, editor.Caret.Offset);
if (path != null && path.Elements.Count > 0) {
var item = path.Elements[path.Elements.Count - 1];
string attribute = XmlParser.GetAttributeNameAtIndex(editor.Document.Text, editor.Caret.Offset);
var e = ResolveAttribute(attribute, editor) as IEvent;
if (e == null)
if (context.Path != null) {
var item = context.Path.Elements.LastOrDefault();
var evt = ResolveAttribute(context.AttributeName, context) as IEvent;
if (evt == null)
break;
string name = Utils.GetAttributeValue(editor.Document.Text, editor.Caret.Offset, "name");
yield return new NewEventCompletionItem(e, (string.IsNullOrEmpty(name)) ? item.Name : name);
foreach (var eventItem in CompletionDataHelper.AddMatchingEventHandlers(editor, invoker))
int offset = XmlParser.GetActiveElementStartIndex(context.Editor.Document.Text, context.Editor.Caret.Offset);
if (offset == -1)
break;
var loc = context.Editor.Document.OffsetToPosition(offset);
string prefix = Utils.GetXamlNamespacePrefix(context);
string name = Utils.GetAttributeValue(context.Editor.Document.Text, loc.Line, loc.Column + 1, "name");
if (string.IsNullOrEmpty(name))
name = Utils.GetAttributeValue(context.Editor.Document.Text, loc.Line, loc.Column + 1, (string.IsNullOrEmpty(prefix) ? "" : prefix + ":") + "name");
yield return new NewEventCompletionItem(evt, (string.IsNullOrEmpty(name)) ? item.Name : name);
foreach (var eventItem in CompletionDataHelper.AddMatchingEventHandlers(context.Editor, invoker))
yield return eventItem;
}
}
break;
}
switch (c.FullyQualifiedName) {
case "System.Windows.Media.Brush":
foreach (var item in typeof(System.Windows.Media.Brushes).GetProperties()) {
yield return new DefaultCompletionItem(item.Name);
}
break;
case "System.Windows.Media.Color":
foreach (var item in typeof(System.Windows.Media.Colors).GetProperties()) {
yield return new DefaultCompletionItem(item.Name);
}
break;
}
}
static IEntity ResolveAttribute(string attribute, ITextEditor editor)
static IEntity ResolveAttribute(string attribute, XamlCompletionContext context)
{
XamlResolver resolver = new XamlResolver();
var path = XmlParser.GetActiveElementStartPathAtIndex(editor.Document.Text, editor.Caret.Offset);
var exp = new ExpressionResult(attribute, new XamlExpressionContext(path, attribute, false));
var info = ParserService.GetParseInformation(editor.FileName);
var mrr = resolver.Resolve(exp, info, editor.Document.Text) as MemberResolveResult;
var exp = new ExpressionResult(attribute, context);
var mrr = resolver.Resolve(exp, context.ParseInformation, context.Editor.Document.Text) as MemberResolveResult;
return mrr.ResolvedMember;
}
static void DoStaticExtensionCompletion(XamlCompletionItemList list, XamlContext context, ParseInformation info, ITextEditor editor)
static void DoStaticExtensionCompletion(XamlCompletionItemList list, XamlCompletionContext context)
{
AttributeValue selItem = context.AttributeValue.ExtensionValue.PositionalArguments.LastOrDefault();
if (context.PressedKey == '.') {
if (selItem != null && selItem.IsString) {
var rr = ResolveStringValue(selItem.StringValue, context.Path, info, editor) as TypeResolveResult;
var rr = ResolveStringValue(selItem.StringValue, context) as TypeResolveResult;
if (rr != null)
list.Items.AddRange(MemberCompletion(editor, rr.ResolvedType));
list.Items.AddRange(MemberCompletion(context, rr.ResolvedType));
}
} else {
if (selItem != null && selItem.IsString) {
int index = selItem.StringValue.IndexOf('.');
string s = (index > -1) ? selItem.StringValue.Substring(0, index) : selItem.StringValue;
var rr = ResolveStringValue(s, context.Path, info, editor) as TypeResolveResult;
var rr = ResolveStringValue(s, context) as TypeResolveResult;
if (rr != null) {
list.Items.AddRange(MemberCompletion(editor, rr.ResolvedType));
list.Items.AddRange(MemberCompletion(context, rr.ResolvedType));
list.PreselectionLength = selItem.StringValue.Length - index - 1;
list.SuggestedItem = list.Items.FirstOrDefault(item => item.Text.StartsWith(selItem.StringValue.Substring(index + 1), StringComparison.OrdinalIgnoreCase));
} else
DoStaticTypeCompletion(selItem, list, info, editor);
DoStaticTypeCompletion(selItem, list, context.ParseInformation, context.Editor);
} else {
DoStaticTypeCompletion(selItem, list, info, editor);
DoStaticTypeCompletion(selItem, list, context.ParseInformation, context.Editor);
}
}
}
@ -401,7 +573,9 @@ namespace ICSharpCode.XamlBinding @@ -401,7 +573,9 @@ namespace ICSharpCode.XamlBinding
{
var items = GetClassesFromContext(info, editor.Document.Text, editor.Caret.Line, editor.Caret.Column);
foreach (var ns in items) {
list.Items.AddRange(ns.Value.Where(c => c.Fields.Any(f => f.IsStatic) || c.Properties.Any(p => p.IsStatic)).Select(c => new XamlCompletionItem(c, ns.Key) as ICompletionItem));
list.Items.AddRange(ns.Value.Where(c => c.Fields.Any(f => f.IsStatic) || c.Properties.Any(p => p.IsStatic))
.Select(c => new XamlCodeCompletionItem(c, ns.Key, false))
.Cast<ICompletionItem>());
}
if (selItem != null && selItem.IsString) {
string s = selItem.StringValue;
@ -410,10 +584,10 @@ namespace ICSharpCode.XamlBinding @@ -410,10 +584,10 @@ namespace ICSharpCode.XamlBinding
}
}
static ResolveResult ResolveStringValue(string value, XmlElementPath path, ParseInformation info, ITextEditor editor)
static ResolveResult ResolveStringValue(string value, XamlCompletionContext context)
{
var resolver = new XamlResolver();
var rr = resolver.Resolve(new ExpressionResult(value, new XamlExpressionContext(path, string.Empty, false)), info, editor.Document.Text);
var rr = resolver.Resolve(new ExpressionResult(value, context), context.ParseInformation, context.Editor.Document.Text);
return rr;
}
@ -422,30 +596,19 @@ namespace ICSharpCode.XamlBinding @@ -422,30 +596,19 @@ namespace ICSharpCode.XamlBinding
return null;
}
public static MarkupExtensionInfo GetInnermostMarkup(MarkupExtensionInfo markup)
public static TypeResolveResult ResolveMarkupExtensionType(MarkupExtensionInfo markup, XamlCompletionContext context)
{
var lastPair = markup.NamedArguments.LastOrDefault();
var last = markup.PositionalArguments.LastOrDefault();
if (markup.NamedArguments.Count > 0)
last = lastPair.Value;
if (last != null) {
if (!last.IsString) {
return GetInnermostMarkup(last.ExtensionValue);
}
}
XamlResolver resolver = new XamlResolver();
TypeResolveResult trr = resolver.Resolve(new ExpressionResult(markup.ExtensionType, context), context.ParseInformation, context.Editor.Document.Text) as TypeResolveResult;
if (trr == null) trr = resolver.Resolve(new ExpressionResult(markup.ExtensionType + "Extension", context), context.ParseInformation, context.Editor.Document.Text) as TypeResolveResult;
return markup;
return trr;
}
static TypeResolveResult ResolveMarkupExtensionType(MarkupExtensionInfo markup, ParseInformation info, ITextEditor editor, XmlElementPath path)
public static TypeResolveResult ResolveType(string name, XamlCompletionContext context)
{
XamlResolver resolver = new XamlResolver();
TypeResolveResult trr = resolver.Resolve(new ExpressionResult(markup.ExtensionType, new XamlExpressionContext(path, null, false)), info, editor.Document.Text) as TypeResolveResult;
if (trr == null) trr = resolver.Resolve(new ExpressionResult(markup.ExtensionType + "Extension", new XamlExpressionContext(path, null, false)), info, editor.Document.Text) as TypeResolveResult;
return trr;
return new XamlResolver()
.Resolve(new ExpressionResult(name, context), context.ParseInformation, context.Editor.Document.Text) as TypeResolveResult;
}
public static IEnumerable<ICompletionItem> AddMatchingEventHandlers(ITextEditor editor, IMethod delegateInvoker)
@ -473,7 +636,7 @@ namespace ICSharpCode.XamlBinding @@ -473,7 +636,7 @@ namespace ICSharpCode.XamlBinding
break;
}
if (equal) {
yield return new XamlCompletionItem(m);
yield return new XamlCodeCompletionItem(m);
}
}
}
@ -491,15 +654,22 @@ namespace ICSharpCode.XamlBinding @@ -491,15 +654,22 @@ namespace ICSharpCode.XamlBinding
return result;
}
static IDictionary<string, IEnumerable<IClass>> GetClassesFromContext(ParseInformation parseInfo, string fileContent, int caretLine, int caretColumn)
static string GetPrefixForNamespace(string @namespace, string fileContent, int caretLine, int caretColumn)
{
using (XmlTextReader r = new XmlTextReader(new StringReader(fileContent))) {
try {
r.WhitespaceHandling = WhitespaceHandling.Significant;
// move reader to correct position
while (r.Read() && !IsReaderAtTarget(r, caretLine, caretColumn)) { }
} catch (XmlException) {}
using (XmlTextReader r = Utils.CreateReaderAtTarget(fileContent, caretLine, caretColumn)) {
foreach (var item in r.GetNamespacesInScope(XmlNamespaceScope.ExcludeXml)) {
if (item.Value == @namespace) {
return item.Key;
}
}
return string.Empty;
}
}
static IDictionary<string, IEnumerable<IClass>> GetClassesFromContext(ParseInformation parseInfo, string fileContent, int caretLine, int caretColumn)
{
using (XmlTextReader r = Utils.CreateReaderAtTarget(fileContent, caretLine, caretColumn)) {
IProjectContent pc = parseInfo.BestCompilationUnit.ProjectContent;
var result = new Dictionary<string, IEnumerable<IClass>>();
@ -514,15 +684,8 @@ namespace ICSharpCode.XamlBinding @@ -514,15 +684,8 @@ namespace ICSharpCode.XamlBinding
static List<ICompletionItem> GetListOfAttachedProperties(ParseInformation parseInfo, string fileContent, int caretLine, int caretColumn, string[] existingItems)
{
using (XmlTextReader r = new XmlTextReader(new StringReader(fileContent))) {
try {
r.WhitespaceHandling = WhitespaceHandling.Significant;
// move reader to correct position
while (r.Read() && !IsReaderAtTarget(r, caretLine, caretColumn)) { }
}
catch (XmlException) {
}
var result = new List<ICompletionItem>();
using (XmlTextReader r = Utils.CreateReaderAtTarget(fileContent, caretLine, caretColumn)) {
List<ICompletionItem> result = new List<ICompletionItem>();
IProjectContent pc = parseInfo.BestCompilationUnit.ProjectContent;
foreach (var ns in r.GetNamespacesInScope(XmlNamespaceScope.ExcludeXml)) {
@ -561,10 +724,11 @@ namespace ICSharpCode.XamlBinding @@ -561,10 +724,11 @@ namespace ICSharpCode.XamlBinding
string name = (!string.IsNullOrEmpty(ns.Key)) ? ns.Key + ":" : "";
string property = item.Name.Remove(item.Name.Length - "Property".Length);
name += c.Name + "." + item.Name.Remove(item.Name.Length - "Property".Length);
return new XamlCompletionItem(name, new DefaultProperty(c, property) { ReturnType = GetAttachedPropertyType(item, c) } ) as ICompletionItem;
return new XamlCodeCompletionItem(new DefaultProperty(c, property) { ReturnType = GetAttachedPropertyType(item, c) }, name);
}
)
.Where(item => !existingItems.Any(str => str == item.Text))
.Cast<ICompletionItem>()
);
}
}
@ -611,14 +775,15 @@ namespace ICSharpCode.XamlBinding @@ -611,14 +775,15 @@ namespace ICSharpCode.XamlBinding
result.AddRange(attachedEvents
.Select(
item => new XamlCompletionItem(
(string.IsNullOrEmpty(ns.Key) ? "" : ns.Key + ":") + c.Name + "." + item.Name.Remove(item.Name.Length - "Event".Length),
item => new XamlCodeCompletionItem(
new DefaultEvent(c, GetEventNameFromField(item)) {
ReturnType = GetAttachedEventDelegateType(item, c)
}
) as ICompletionItem
},
(string.IsNullOrEmpty(ns.Key) ? "" : ns.Key + ":") + c.Name + "." + item.Name.Remove(item.Name.Length - "Event".Length)
)
)
.Where(item => !existingItems.Any(str => str == item.Text))
.Cast<ICompletionItem>()
);
}
}

30
src/AddIns/BackendBindings/XamlBinding/XamlBinding/Extensions.cs

@ -5,10 +5,13 @@ @@ -5,10 +5,13 @@
// <version>$Revision$</version>
// </file>
using ICSharpCode.SharpDevelop;
using System;
using System.Collections.Generic;
using System.Linq;
using ICSharpCode.SharpDevelop;
using ICSharpCode.SharpDevelop.Dom;
using ICSharpCode.SharpDevelop.Editor.CodeCompletion;
using ICSharpCode.XmlEditor;
namespace ICSharpCode.XamlBinding
@ -36,15 +39,26 @@ namespace ICSharpCode.XamlBinding @@ -36,15 +39,26 @@ namespace ICSharpCode.XamlBinding
return false;
}
public static QualifiedName LastOrDefault(this QualifiedNameCollection collection)
public static IEnumerable<ICompletionItem> RemoveEvents(this IEnumerable<ICompletionItem> list)
{
if (collection == null)
throw new ArgumentNullException("collection");
if (collection.Count > 0)
return collection[collection.Count - 1];
foreach (var item in list) {
if (item is XamlCodeCompletionItem) {
var comItem = item as XamlCodeCompletionItem;
if (!(comItem.Entity is IEvent))
yield return item;
} else yield return item;
}
}
return null;
public static IEnumerable<ICompletionItem> RemoveProperties(this IEnumerable<ICompletionItem> list)
{
foreach (var item in list) {
if (item is XamlCodeCompletionItem) {
var comItem = item as XamlCodeCompletionItem;
if (!(comItem.Entity is IProperty))
yield return item;
} else yield return item;
}
}
}
}

6
src/AddIns/BackendBindings/XamlBinding/XamlBinding/MarkupExtensionInfo.cs

@ -21,8 +21,10 @@ namespace ICSharpCode.XamlBinding @@ -21,8 +21,10 @@ namespace ICSharpCode.XamlBinding
public IList<AttributeValue> PositionalArguments { get; private set; }
public IDictionary<string, AttributeValue> NamedArguments { get; private set; }
public int StartOffset { get; set; }
public MarkupExtensionInfo()
: this(string.Empty, new List<AttributeValue>(), new Dictionary<string, AttributeValue>())
: this(string.Empty, new List<AttributeValue>(), new Dictionary<string, AttributeValue>(StringComparer.OrdinalIgnoreCase))
{
}
@ -39,6 +41,8 @@ namespace ICSharpCode.XamlBinding @@ -39,6 +41,8 @@ namespace ICSharpCode.XamlBinding
string stringValue;
MarkupExtensionInfo extensionValue;
public int StartOffset { get; set; }
public bool IsString {
get { return stringValue != null; }
}

21
src/AddIns/BackendBindings/XamlBinding/XamlBinding/MarkupExtensionParser.cs

@ -19,22 +19,28 @@ namespace ICSharpCode.XamlBinding @@ -19,22 +19,28 @@ namespace ICSharpCode.XamlBinding
var tokenizer = new MarkupExtensionTokenizer(text);
string argumentName = null;
int namedArgsStart = 0;
var token = tokenizer.NextToken();
while (token.Kind != MarkupExtensionTokenKind.EndOfFile) {
switch (token.Kind) {
case MarkupExtensionTokenKind.TypeName:
info.ExtensionType = token.Value;
info.StartOffset = token.StartOffset;
break;
case MarkupExtensionTokenKind.MemberName:
// if there is an open member without a value add the member name
if (argumentName != null)
info.NamedArguments.Add(argumentName, new AttributeValue(string.Empty));
argumentName = token.Value;
namedArgsStart = token.StartOffset;
break;
case MarkupExtensionTokenKind.String:
if (argumentName != null) {
info.NamedArguments.Add(argumentName, ParseValue(token.Value));
info.NamedArguments.Add(argumentName, ParseValue(token.Value, namedArgsStart));
argumentName = null;
} else {
info.PositionalArguments.Add(ParseValue(token.Value));
info.PositionalArguments.Add(ParseValue(token.Value, token.StartOffset));
}
break;
}
@ -48,14 +54,19 @@ namespace ICSharpCode.XamlBinding @@ -48,14 +54,19 @@ namespace ICSharpCode.XamlBinding
}
public static AttributeValue ParseValue(string text)
{
return ParseValue(text, 0);
}
public static AttributeValue ParseValue(string text, int offset)
{
if (string.IsNullOrEmpty(text))
return new AttributeValue(string.Empty);
return new AttributeValue(string.Empty) { StartOffset = offset };
if (text.StartsWith("{", StringComparison.OrdinalIgnoreCase))
return new AttributeValue(Parse(text));
return new AttributeValue(Parse(text)) { StartOffset = offset };
else
return new AttributeValue(text);
return new AttributeValue(text) { StartOffset = offset };
}
}
}

2
src/AddIns/BackendBindings/XamlBinding/XamlBinding/MarkupExtensionToken.cs

@ -14,6 +14,8 @@ namespace ICSharpCode.XamlBinding @@ -14,6 +14,8 @@ namespace ICSharpCode.XamlBinding
public MarkupExtensionTokenKind Kind { get; private set; }
public string Value { get; private set; }
public int StartOffset { get; set; }
public MarkupExtensionToken(MarkupExtensionTokenKind kind, string value)
{
this.Kind = kind;

8
src/AddIns/BackendBindings/XamlBinding/XamlBinding/MarkupExtensionTokenizer.cs

@ -27,6 +27,8 @@ namespace ICSharpCode.XamlBinding @@ -27,6 +27,8 @@ namespace ICSharpCode.XamlBinding
string text;
int pos;
int startPos;
Queue<MarkupExtensionToken> tokens = new Queue<MarkupExtensionToken>();
/// <summary>
@ -51,7 +53,7 @@ namespace ICSharpCode.XamlBinding @@ -51,7 +53,7 @@ namespace ICSharpCode.XamlBinding
void AddToken(MarkupExtensionTokenKind kind, string val)
{
tokens.Enqueue(new MarkupExtensionToken(kind, val));
tokens.Enqueue(new MarkupExtensionToken(kind, val) { StartOffset = startPos });
}
void ParseBeginning()
@ -75,16 +77,20 @@ namespace ICSharpCode.XamlBinding @@ -75,16 +77,20 @@ namespace ICSharpCode.XamlBinding
case '}':
AddToken(MarkupExtensionTokenKind.CloseBrace, "}");
pos++;
startPos = pos;
break;
case '=':
AddToken(MarkupExtensionTokenKind.Equals, "=");
pos++;
startPos = pos;
break;
case ',':
AddToken(MarkupExtensionTokenKind.Comma, ",");
pos++;
startPos = pos;
break;
default:
startPos = pos;
MembernameOrString();
break;
}

271
src/AddIns/BackendBindings/XamlBinding/XamlBinding/Utils.cs

@ -10,9 +10,11 @@ using System.Collections.Generic; @@ -10,9 +10,11 @@ using System.Collections.Generic;
using System.Diagnostics;
using System.IO;
using System.Linq;
using System.Text.RegularExpressions;
using System.Xml;
using ICSharpCode.Core;
using ICSharpCode.SharpDevelop.Editor;
using ICSharpCode.XmlEditor;
namespace ICSharpCode.XamlBinding
@ -22,129 +24,40 @@ namespace ICSharpCode.XamlBinding @@ -22,129 +24,40 @@ namespace ICSharpCode.XamlBinding
/// </summary>
public static class Utils
{
public static bool HasMatchingEndTag(string tagname, string text, int offset)
internal static bool IsReaderAtTarget(XmlTextReader r, int line, int col)
{
int index = XmlParser.GetActiveElementStartIndex(text, offset);
if (index == -1)
return false;
text = text.Substring(index);
var path = XmlParser.GetActiveElementStartPathAtIndex(text, index);
XmlReader reader = XmlTextReader.Create(new StringReader(text));
int startTags = 0;
try {
while (reader.Read()) {
switch (reader.NodeType) {
case XmlNodeType.Element:
if (!reader.IsEmptyElement)
startTags++;
break;
case XmlNodeType.EndElement:
startTags--;
if (startTags == 0 && tagname == reader.Name) {
if (r.LineNumber > line)
return true;
}
break;
}
}
} catch (XmlException e) {
Debug.Print(e.ToString());
else if (r.LineNumber == line)
return r.LinePosition >= col;
else
return false;
}
return false;
}
public static string GetAttributeValue(string text, int offset, string name)
public static string GetAttributeValue(string text, int line, int col, string name)
{
text = SimplifyToSingleElement(text, offset, "Test");
try {
XmlTextReader reader = new XmlTextReader(new StringReader(text));
reader.XmlResolver = null;
if (text == null)
return null;
while (reader.Read() && !IsReaderAtTarget(reader, line, col)) { }
XmlReader reader = XmlTextReader.Create(new StringReader(text));
try {
reader.ReadToFollowing("Test");
if (!reader.MoveToFirstAttribute())
return null;
do {
LoggingService.Debug("name: " + reader.Name + " value: " + reader.Value);
int start = reader.Name.IndexOf(':') + 1;
string plainName = reader.Name.Substring(start, reader.Name.Length - start).ToUpperInvariant();
string plainName = reader.Name.ToUpperInvariant();
if (plainName == name.ToUpperInvariant())
return reader.Value;
} while (reader.MoveToNextAttribute());
} catch (XmlException) { }
return null;
}
public static Dictionary<string, string> GetXmlNamespacesForOffset(string fileContent, int offset)
{
if (fileContent == null)
throw new ArgumentNullException("fileContent");
if (offset < 0 || offset > fileContent.Length)
throw new ArgumentOutOfRangeException("offset", offset, "Value must be between 0 and " + fileContent.Length);
var map = new Dictionary<string, string>();
int endIndex = fileContent.IndexOfAny(new char[] {'<', '>'}, offset);
if (endIndex > -1)
fileContent = fileContent.Substring(0, endIndex + 1);
int lastWhiteSpacePos = fileContent.LastIndexOfAny(new char[] {' ', '\t', '\n', '\r'});
bool inDouble = false, inSingle = false;
for (int i = 0; i < fileContent.Length; i++) {
if (fileContent[i] == '"' && !inSingle)
inDouble = !inDouble;
if (fileContent[i] == '\'' && !inDouble)
inSingle = !inSingle;
if (fileContent[i] == '>') {
int lastDelimiterPos = fileContent.Substring(0, i + 1).LastIndexOfAny(new char[] {'>', '/'});
if (inDouble) {
fileContent.Insert(lastDelimiterPos, "\"");
i++;
inDouble = false;
}
if (inSingle) {
fileContent.Insert(lastDelimiterPos, "'");
inSingle = false;
i++;
}
}
}
fileContent = fileContent.Replace("<?", " ").Replace("?>", " ").Replace("<", " ").Replace("/>", " ").Replace(">", " ").Replace("\n", " ").Replace("\r", " ").Replace("\t", " ");
while (fileContent.Contains(" "))
fileContent = fileContent.Replace(" ", " ");
fileContent = fileContent.Replace("= \"", "=\"");
fileContent = fileContent.Replace(" =\"", "=\"");
Debug.Print(fileContent);
string[] data = fileContent.Split(' ');
var filter1 = data.Where(s => s.StartsWith("xmlns"));
foreach (string item in filter1) {
string[] parts = item.Split(new char[] {'='}, 2);
if (parts.Length == 2) {
if (map.ContainsKey(parts[0])) // replace namespace with new one
map.Remove(parts[0]);
map.Add(parts[0], parts[1].Trim('"', '\''));
}
} catch (XmlException e) {
Debug.Print(e.ToString());
}
return map;
return null;
}
public static int GetOffsetFromValueStart(string xaml, int offset)
@ -162,20 +75,15 @@ namespace ICSharpCode.XamlBinding @@ -162,20 +75,15 @@ namespace ICSharpCode.XamlBinding
return offset - start - 1;
}
public static string[] GetListOfExistingAttributeNames(string text, int offset)
public static string[] GetListOfExistingAttributeNames(string text, int line, int col)
{
List<string> list = new List<string>();
text = SimplifyToSingleElement(text, offset, "Test");
if (text == null)
return list.ToArray();
XmlReader reader = XmlTextReader.Create(new StringReader(text));
using (XmlReader reader = CreateReaderAtTarget(text, line, col)) {
try {
reader.ReadToFollowing("Test");
if (!reader.MoveToFirstAttribute())
return list.ToArray();
@ -183,7 +91,13 @@ namespace ICSharpCode.XamlBinding @@ -183,7 +91,13 @@ namespace ICSharpCode.XamlBinding
LoggingService.Debug("name: " + reader.Name + " value: " + reader.Value);
list.Add(reader.Name);
} while (reader.MoveToNextAttribute());
} catch (XmlException) { }
} catch (XmlException e) {
Debug.Print(e.ToString());
}
}
foreach (var item in list)
Debug.Print(item);
return list.ToArray();
}
@ -204,29 +118,14 @@ namespace ICSharpCode.XamlBinding @@ -204,29 +118,14 @@ namespace ICSharpCode.XamlBinding
return startIndex;
}
static string SimplifyToSingleElement(string text, int offset, string name)
{
int index = XmlParser.GetActiveElementStartIndex(text, offset);
if (index == -1) return null;
index = text.IndexOf(' ', index);
if (index == -1) return null;
text = text.Substring(index);
int endIndex = text.IndexOfAny(new char[] { '<', '>' });
if (endIndex == -1) return null;
text = text.Substring(0, endIndex).Trim(' ', '\t', '\n', '\r', '/');
LoggingService.Debug("text: '" + text + "'");
text = "<" + name + " " + text + " />";
static char[] whitespace = new char[] {' ', '\t', '\n', '\r'};
return text;
}
public static string GetXamlNamespacePrefix(string xaml, int offset)
public static string GetXamlNamespacePrefix(XamlContext context)
{
var list = Utils.GetXmlNamespacesForOffset(xaml, offset);
var item = list.FirstOrDefault(i => i.Value == CompletionDataHelper.XamlNamespace);
var item = context.XmlnsDefinitions.FirstOrDefault(i => i.Value == CompletionDataHelper.XamlNamespace);
if (item.Key.StartsWith("xmlns:", StringComparison.OrdinalIgnoreCase))
return item.Key.Substring("xmlns:".Length);
if (item.Key != null)
return item.Key;
return string.Empty;
}
@ -237,7 +136,7 @@ namespace ICSharpCode.XamlBinding @@ -237,7 +136,7 @@ namespace ICSharpCode.XamlBinding
if (offset < 0)
throw new ArgumentOutOfRangeException("offset", offset, "Value must be between 0 and " + (xaml.Length - 1));
if (offset >= xaml.Length)
if (offset >= xaml.Length && offset > 0)
offset = xaml.Length - 1;
string interestingPart = xaml.Substring(0, offset);
@ -247,5 +146,113 @@ namespace ICSharpCode.XamlBinding @@ -247,5 +146,113 @@ namespace ICSharpCode.XamlBinding
return interestingPart.LastIndexOf("<!--", StringComparison.OrdinalIgnoreCase) != -1;
}
public static int GetOffsetFromFilePos(string content, int line, int col)
{
if (line < 1)
return 0;
if (line == 1)
return (col > 0) ? col - 1 : 0;
int offset = -1;
while (line > 1) {
int tmp = content.IndexOf('\n', offset + 1);
if (tmp > -1) {
offset = tmp;
line--;
} else {
return content.Length;
}
}
return offset + col - 1;
}
public static int GetParentElementStart(ITextEditor editor)
{
Stack<int> offsetStack = new Stack<int>();
using (XmlTextReader xmlReader = new XmlTextReader(new StringReader(editor.Document.GetText(0, editor.Caret.Offset)))) {
try {
xmlReader.XmlResolver = null; // prevent XmlTextReader from loading external DTDs
while (xmlReader.Read()) {
switch (xmlReader.NodeType) {
case XmlNodeType.Element:
if (!xmlReader.IsEmptyElement) {
offsetStack.Push(editor.Document.PositionToOffset(xmlReader.LineNumber, xmlReader.LinePosition));
}
break;
case XmlNodeType.EndElement:
offsetStack.Pop();
break;
}
}
} catch (XmlException) { }
}
return (offsetStack.Count > 0) ? offsetStack.Pop() : -1;
}
public static XmlTextReader CreateReaderAtTarget(string fileContent, int caretLine, int caretColumn)
{
XmlTextReader r = new XmlTextReader(new StringReader(fileContent));
r.XmlResolver = null;
try {
r.WhitespaceHandling = WhitespaceHandling.Significant;
// move reader to correct position
while (r.Read() && !IsReaderAtTarget(r, caretLine, caretColumn)) { }
} catch (XmlException) {}
return r;
}
public static MarkupExtensionInfo GetInnermostMarkup(MarkupExtensionInfo markup)
{
var last = markup.PositionalArguments.LastOrDefault();
if (markup.NamedArguments.Count > 0)
last = markup.NamedArguments.LastOrDefault().Value;
if (last != null) {
if (!last.IsString) {
return GetInnermostMarkup(last.ExtensionValue);
}
}
return markup;
}
/// <summary>
/// Gets the of a markup extension at the given position.
/// </summary>
/// <param name="info">The markup extension data to parse.</param>
/// <param name="offset">The offset to look at.</param>
/// <returns>
/// A string, if the at offset is the extension type. <br />
/// An AttributeValue, if at the offset is a positional argument. <br />
/// A KeyValuePair&lt;string, AttributeValue&gt;, if at the offset is a named argument.
/// </returns>
public static object GetMarkupDataAtPosition(MarkupExtensionInfo info, int offset)
{
object previous = info.ExtensionType;
Debug.Print("offset: " + offset);
foreach (var item in info.PositionalArguments) {
if (item.StartOffset > offset)
break;
previous = item.IsString ? item : GetMarkupDataAtPosition(item.ExtensionValue, offset - item.StartOffset);
}
foreach (var pair in info.NamedArguments) {
if (pair.Value.StartOffset > offset)
break;
previous = pair.Value.IsString ? pair.Value : GetMarkupDataAtPosition(pair.Value.ExtensionValue, offset - pair.Value.StartOffset);
}
return previous;
}
}
}

4
src/AddIns/BackendBindings/XamlBinding/XamlBinding/XamlBinding.addin

@ -41,4 +41,8 @@ @@ -41,4 +41,8 @@
<Path name = "/AddIns/DefaultTextEditor/CodeCompletion">
<CodeCompletionBinding id = "Xaml" extensions = ".xaml" class = "ICSharpCode.XamlBinding.XamlCodeCompletionBinding"/>
</Path>
<Path name = "/AddIns/DefaultTextEditor/Formatter/XML">
<Class id ="XmlFormatter" class = "ICSharpCode.XmlEditor.XmlFormattingStrategy"/>
</Path>
</AddIn>

1
src/AddIns/BackendBindings/XamlBinding/XamlBinding/XamlBinding.csproj

@ -80,7 +80,6 @@ @@ -80,7 +80,6 @@
<Compile Include="XamlContext.cs" />
<Compile Include="XamlExpressionContext.cs" />
<Compile Include="XamlExpressionFinder.cs">
<DependentUpon>XamlExpressionContext.cs</DependentUpon>
</Compile>
<Compile Include="XamlColorizer.cs" />
<Compile Include="MarkupExtensionParseException.cs" />

127
src/AddIns/BackendBindings/XamlBinding/XamlBinding/XamlCodeCompletionBinding.cs

@ -5,13 +5,15 @@ @@ -5,13 +5,15 @@
// <version>$Revision: 3731 $</version>
// </file>
using ICSharpCode.SharpDevelop.Editor.CodeCompletion;
using System;
using System.Collections.Generic;
using System.Globalization;
using System.Linq;
using ICSharpCode.SharpDevelop;
using ICSharpCode.SharpDevelop.Dom;
using ICSharpCode.SharpDevelop.Editor;
using ICSharpCode.SharpDevelop.Editor.CodeCompletion;
using ICSharpCode.XmlEditor;
namespace ICSharpCode.XamlBinding
@ -33,7 +35,7 @@ namespace ICSharpCode.XamlBinding @@ -33,7 +35,7 @@ namespace ICSharpCode.XamlBinding
{
ParseInformation info = ParserService.GetParseInformation(editor.FileName);
XamlContext context = CompletionDataHelper.ResolveContext(editor, ch);
XamlCompletionContext context = CompletionDataHelper.ResolveCompletionContext(editor, ch);
ICompletionItemList list;
if (context.Description == XamlContextDescription.InComment)
@ -41,13 +43,12 @@ namespace ICSharpCode.XamlBinding @@ -41,13 +43,12 @@ namespace ICSharpCode.XamlBinding
switch (ch) {
case '<':
context.Description = (context.Description == XamlContextDescription.None) ? XamlContextDescription.AtTag : context.Description;
list = CompletionDataHelper.CreateListForContext(editor, context);
editor.ShowCompletionWindow(list);
return CodeCompletionKeyPressResult.Completed;
case '>': // XML tag completion
if (DoXmlTagCompletion(editor))
return CodeCompletionKeyPressResult.EatKey;
break;
case '>':
return CodeCompletionKeyPressResult.None;
case '"':
if (!XmlParser.IsInsideAttributeValue(editor.Document.Text, editor.Caret.Offset)) {
int search = editor.Caret.Offset + 1;
@ -71,12 +72,13 @@ namespace ICSharpCode.XamlBinding @@ -71,12 +72,13 @@ namespace ICSharpCode.XamlBinding
editor.Document.Insert(editor.Caret.Offset, "{}");
editor.Caret.Offset--;
DoMarkupExtensionCompletion(editor, info, CompletionDataHelper.ResolveContext(editor, '{'));
DoMarkupExtensionCompletion(editor, info, CompletionDataHelper.ResolveCompletionContext(editor, '{'));
return CodeCompletionKeyPressResult.EatKey;
}
break;
case '.':
if (context.Path != null && !XmlParser.IsInsideAttributeValue(editor.Document.Text, editor.Caret.Offset)) {
context.Description = XamlContextDescription.AtTag;
list = CompletionDataHelper.CreateListForContext(editor, context);
editor.ShowCompletionWindow(list);
return CodeCompletionKeyPressResult.Completed;
@ -84,20 +86,26 @@ namespace ICSharpCode.XamlBinding @@ -84,20 +86,26 @@ namespace ICSharpCode.XamlBinding
break;
case ':':
if (context.Path != null && XmlParser.GetQualifiedAttributeNameAtIndex(editor.Document.Text, editor.Caret.Offset) == null) {
if (!context.AttributeName.StartsWith("xmlns")) {
list = CompletionDataHelper.CreateListForContext(editor, context);
editor.ShowCompletionWindow(list);
return CodeCompletionKeyPressResult.CompletedIncludeKeyInCompletion;
}
}
break;
case '/': // ignore '/' when trying to type '/>'
return CodeCompletionKeyPressResult.None;
case '=':
if (!XmlParser.IsInsideAttributeValue(editor.Document.Text, editor.Caret.Offset)) {
int searchOffset = editor.Caret.Offset + 1;
while (char.IsWhiteSpace(editor.Document.GetCharAt(searchOffset)))
int searchOffset = editor.Caret.Offset;
while (searchOffset < editor.Document.TextLength - 1) {
searchOffset++;
if (!char.IsWhiteSpace(editor.Document.GetCharAt(searchOffset)))
break;
}
if (editor.Document.GetCharAt(searchOffset) != '"') {
if (searchOffset >= editor.Document.TextLength || editor.Document.GetCharAt(searchOffset) != '"') {
editor.Document.Insert(editor.Caret.Offset, "=\"\"");
editor.Caret.Offset--;
} else {
@ -110,50 +118,28 @@ namespace ICSharpCode.XamlBinding @@ -110,50 +118,28 @@ namespace ICSharpCode.XamlBinding
}
break;
default:
if (context.Description != XamlContextDescription.None && !char.IsWhiteSpace(context.PressedKey)) {
editor.Document.Insert(editor.Caret.Offset, ch.ToString());
if (!context.AttributeName.StartsWith("xmlns"))
this.CtrlSpace(editor);
return CodeCompletionKeyPressResult.EatKey;
}
return CodeCompletionKeyPressResult.None;
}
static bool DoXmlTagCompletion(ITextEditor editor)
{
int offset = editor.Caret.Offset;
if (offset > 0) {
int searchOffset = offset - 1;
char c = editor.Document.GetCharAt(searchOffset);
while (char.IsWhiteSpace(c)) {
searchOffset--;
c = editor.Document.GetCharAt(searchOffset);
}
if (c != '/') {
string document = editor.Document.Text.Insert(offset, ">");
XmlElementPath path = XmlParser.GetActiveElementStartPathAtIndex(document, offset);
if (path != null && path.Elements.Count > 0) {
QualifiedName last = path.Elements[path.Elements.Count - 1];
if (!Utils.HasMatchingEndTag(last.Name, document, offset) && !last.Name.StartsWith("/") && !last.Name.StartsWith("!--")) {
editor.Document.Insert(offset, "></" + last.Name + ">");
editor.Caret.Offset = offset + 1;
return true;
}
}
}
break;
}
return false;
return CodeCompletionKeyPressResult.None;
}
public bool CtrlSpace(ITextEditor editor)
{
XamlContext context = CompletionDataHelper.ResolveContext(editor, ' ');
XamlCompletionContext context = CompletionDataHelper.ResolveCompletionContext(editor, ' ');
context.Forced = true;
var info = ParserService.GetParseInformation(editor.FileName);
if (context.Path != null) {
if (!XmlParser.IsInsideAttributeValue(editor.Document.Text, editor.Caret.Offset)) {
var list = CompletionDataHelper.CreateListForContext(editor, context) as XamlCompletionItemList;
string starter = editor.GetWordBeforeCaret().Trim('<');
string starter = editor.GetWordBeforeCaret().Trim('<', '>');
if (!string.IsNullOrEmpty(starter) && !starter.EndsWith(StringComparison.Ordinal, ' ', '\t', '\n', '\r'))
list.PreselectionLength = starter.Length;
editor.ShowCompletionWindow(list);
@ -167,15 +153,51 @@ namespace ICSharpCode.XamlBinding @@ -167,15 +153,51 @@ namespace ICSharpCode.XamlBinding
if (!DoMarkupExtensionCompletion(editor, info, context)) {
XamlResolver resolver = new XamlResolver();
var mrr = resolver.Resolve(new ExpressionResult(context.AttributeName, new XamlExpressionContext(context.Path, context.AttributeName, false)),
info, editor.Document.Text) as MemberResolveResult;
var completionList = new XamlCompletionItemList();
var mrr = resolver.Resolve(new ExpressionResult(context.AttributeName, context),
context.ParseInformation, context.Editor.Document.Text) as MemberResolveResult;
if (mrr != null && mrr.ResolvedType != null) {
var c = mrr.ResolvedType.GetUnderlyingClass();
var completionList = new XamlCompletionItemList();
completionList.Items.AddRange(CompletionDataHelper.MemberCompletion(editor, mrr.ResolvedType));
editor.ShowCompletionWindow(completionList);
completionList.Items.AddRange(CompletionDataHelper.MemberCompletion(context, mrr.ResolvedType));
editor.ShowInsightWindow(CompletionDataHelper.MemberInsight(mrr));
}
if (context.AttributeName == "Property" && context.Path.Elements.LastOrDefault().Name == "Setter") {
int offset = Utils.GetParentElementStart(editor);
var loc = editor.Document.OffsetToPosition(offset);
string[] attributes = Utils.GetListOfExistingAttributeNames(editor.Document.Text, loc.Line, loc.Column);
if (attributes.Contains("TargetType")) {
AttributeValue value = MarkupExtensionParser.ParseValue(Utils.GetAttributeValue(editor.Document.Text, loc.Line, loc.Column, "TargetType"));
if (!value.IsString) {
TypeResolveResult trr = CompletionDataHelper.ResolveMarkupExtensionType(value.ExtensionValue, context);
var typeName = CompletionDataHelper.ResolveType(GetTypeNameFromTypeExtension(value.ExtensionValue), context);
if (trr != null && trr.ResolvedClass != null && trr.ResolvedClass.FullyQualifiedName == "System.Windows.Markup.TypeExtension"
&& typeName != null && typeName != null) {
completionList.Items.AddRange(
typeName.ResolvedClass.Properties
.Where(p => p.IsPublic && p.CanSet)
.Select(prop => new DefaultCompletionItem(prop.Name))
.Cast<ICompletionItem>()
);
}
}
}
}
if (context.AttributeName.StartsWith("xmlns"))
completionList.Items.AddRange(CompletionDataHelper.CreateListForXmlnsCompletion(info.BestCompilationUnit.ProjectContent));
ICompletionListWindow window = editor.ShowCompletionWindow(completionList);
if (context.AttributeName.StartsWith("xmlns"))
window.Width = double.NaN;
return true;
}
}
}
@ -183,7 +205,22 @@ namespace ICSharpCode.XamlBinding @@ -183,7 +205,22 @@ namespace ICSharpCode.XamlBinding
return false;
}
static bool DoMarkupExtensionCompletion(ITextEditor editor, ParseInformation info, XamlContext context)
static string GetTypeNameFromTypeExtension(MarkupExtensionInfo info)
{
var item = info.PositionalArguments.FirstOrDefault();
if (item != null && item.IsString) {
return item.StringValue;
} else {
if (info.NamedArguments.TryGetValue("typename", out item)) {
if (item.IsString)
return item.StringValue;
}
}
return string.Empty;
}
static bool DoMarkupExtensionCompletion(ITextEditor editor, ParseInformation info, XamlCompletionContext context)
{
if (context.AttributeValue != null && !context.AttributeValue.IsString) {
var completionList = CompletionDataHelper.CreateMarkupExtensionCompletion(context, info, editor);

16
src/AddIns/BackendBindings/XamlBinding/XamlBinding/XamlColorizer.cs

@ -65,7 +65,7 @@ namespace ICSharpCode.XamlBinding @@ -65,7 +65,7 @@ namespace ICSharpCode.XamlBinding
{
int index = -1;
List<HighlightingInfo> infos = new List<HighlightingInfo>();
/*
do {
index = line.Text.IndexOf('=', index + 1);
if (index > -1) {
@ -76,7 +76,7 @@ namespace ICSharpCode.XamlBinding @@ -76,7 +76,7 @@ namespace ICSharpCode.XamlBinding
infos.Add(new HighlightingInfo(expr, startIndex, startIndex + expr.Length, line.Offset, path));
}
}
} while (index > -1);
} while (index > -1);*/
return infos.ToArray();
}
@ -105,15 +105,15 @@ namespace ICSharpCode.XamlBinding @@ -105,15 +105,15 @@ namespace ICSharpCode.XamlBinding
int startOffset;
int endOffset;
int lineOffset;
XmlElementPath path;
XamlContext context;
public HighlightingInfo(string token, int startOffset, int endOffset, int lineOffset, XmlElementPath path)
public HighlightingInfo(string token, int startOffset, int endOffset, int lineOffset, XamlContext context)
{
this.token = token;
this.startOffset = startOffset;
this.endOffset = endOffset;
this.lineOffset = lineOffset;
this.path = path;
this.context = context;
}
public string Token {
@ -132,12 +132,12 @@ namespace ICSharpCode.XamlBinding @@ -132,12 +132,12 @@ namespace ICSharpCode.XamlBinding
get { return lineOffset; }
}
public XmlElementPath Path {
get { return path; }
public XamlContext Context {
get { return context; }
}
public ExpressionResult GetExpressionResult() {
return new ExpressionResult(token, new XamlExpressionContext(path, token, false));
return new ExpressionResult(token, context);
}
}
}

91
src/AddIns/BackendBindings/XamlBinding/XamlBinding/XamlCompletionItem.cs

@ -14,24 +14,27 @@ using ICSharpCode.SharpDevelop.Editor; @@ -14,24 +14,27 @@ using ICSharpCode.SharpDevelop.Editor;
namespace ICSharpCode.XamlBinding
{
class XamlCompletionItem : CodeCompletionItem
class XamlCodeCompletionItem : CodeCompletionItem
{
public XamlCompletionItem(IEntity entity, string prefix)
public XamlCodeCompletionItem(IEntity entity, string prefix, bool addOpeningBrace)
: base(entity)
{
if (string.IsNullOrEmpty(prefix))
this.Text = entity.Name;
else
this.Text = prefix + ":" + entity.Name;
if (addOpeningBrace)
this.Text = "<" + this.Text;
}
public XamlCompletionItem(IEntity entity)
public XamlCodeCompletionItem(IEntity entity)
: base(entity)
{
this.Text = entity.Name;
}
public XamlCompletionItem(string text, IEntity entity)
public XamlCodeCompletionItem(IEntity entity, string text)
: base(entity)
{
this.Text = text;
@ -43,6 +46,86 @@ namespace ICSharpCode.XamlBinding @@ -43,6 +46,86 @@ namespace ICSharpCode.XamlBinding
}
}
class XamlCompletionItem : DefaultCompletionItem
{
string prefix, @namespace, name;
public XamlCompletionItem(string prefix, string @namespace, string name)
: base(prefix + ":" + name)
{
this.prefix = prefix;
this.@namespace = @namespace;
this.name = name;
}
public XamlCompletionItem(string @namespace, string name)
: base(name)
{
this.prefix = "";
this.@namespace = @namespace;
this.name = name;
}
public string Prefix {
get { return prefix; }
}
public string Namespace {
get { return @namespace; }
}
public string Name {
get { return name; }
}
}
class XmlnsCompletionItem : DefaultCompletionItem
{
string @namespace, assembly;
bool isUrl;
public bool IsUrl {
get { return isUrl; }
}
public XmlnsCompletionItem(string @namespace, string assembly)
: base(@namespace + " (" + assembly + ")")
{
this.@namespace = @namespace;
this.assembly = assembly;
}
public XmlnsCompletionItem(string @namespace, bool isUrl)
: base(@namespace)
{
this.@namespace = @namespace;
this.isUrl = isUrl;
this.assembly = string.Empty;
}
public string Namespace {
get { return @namespace; }
}
public string Assembly {
get { return assembly; }
}
public override void Complete(CompletionContext context)
{
if (isUrl)
base.Complete(context);
else {
ITextEditor editor = context.Editor;
string newText = "clr-namespace:" + @namespace;
if (!string.IsNullOrEmpty(assembly))
newText += ";assembly=" + assembly;
editor.Document.Replace(context.StartOffset, context.Length, newText);
context.EndOffset = context.StartOffset + newText.Length;
}
}
}
class NewEventCompletionItem : DefaultCompletionItem
{
IEvent eventType;

31
src/AddIns/BackendBindings/XamlBinding/XamlBinding/XamlCompletionItemList.cs

@ -26,7 +26,7 @@ namespace ICSharpCode.XamlBinding @@ -26,7 +26,7 @@ namespace ICSharpCode.XamlBinding
public override CompletionItemListKeyResult ProcessInput(char key)
{
if (key == ':')
if (key == ':' || key == '/')
return CompletionItemListKeyResult.NormalKey;
return base.ProcessInput(key);
@ -36,8 +36,8 @@ namespace ICSharpCode.XamlBinding @@ -36,8 +36,8 @@ namespace ICSharpCode.XamlBinding
{
base.Complete(context, item);
if (item is XamlCompletionItem) {
XamlCompletionItem cItem = item as XamlCompletionItem;
if (item is XamlCodeCompletionItem) {
XamlCodeCompletionItem cItem = item as XamlCodeCompletionItem;
if (cItem.Entity is IProperty || cItem.Entity is IEvent) {
if (context.Editor.Document.GetCharAt(context.StartOffset - 1) != '.') {
@ -45,17 +45,22 @@ namespace ICSharpCode.XamlBinding @@ -45,17 +45,22 @@ namespace ICSharpCode.XamlBinding
context.Editor.Document.Insert(context.EndOffset, "=\"\"");
context.Editor.Caret.Offset--;
} else {
XamlContext xamlContext = CompletionDataHelper.ResolveContext(context.Editor, context.CompletionChar);
XamlCompletionContext xamlContext = CompletionDataHelper.ResolveCompletionContext(context.Editor, context.CompletionChar);
if (!string.IsNullOrEmpty(xamlContext.RawAttributeValue)) {
string valuePart = xamlContext.RawAttributeValue.Substring(0, xamlContext.ValueStartOffset);
AttributeValue value = MarkupExtensionParser.ParseValue(valuePart);
if (value != null && !value.IsString) {
var markup = CompletionDataHelper.GetInnermostMarkup(value.ExtensionValue);
var markup = Utils.GetInnermostMarkup(value.ExtensionValue);
if (markup.NamedArguments.Count > 0 || markup.PositionalArguments.Count > 0) {
int oldOffset = context.Editor.Caret.Offset;
context.Editor.Caret.Offset = context.StartOffset;
string word = context.Editor.GetWordBeforeCaret();
string word = context.Editor.GetWordBeforeCaret().Trim();
if (!word.EndsWith(",") && markup.ExtensionType != word) {
context.Editor.Document.Insert(context.Editor.Caret.Offset, ", ");
oldOffset += 2;
}
context.Editor.Caret.Offset = oldOffset;
}
@ -75,7 +80,7 @@ namespace ICSharpCode.XamlBinding @@ -75,7 +80,7 @@ namespace ICSharpCode.XamlBinding
insertionString = " ";
}
string prefix = Utils.GetXamlNamespacePrefix(context.Editor.Document.Text, context.StartOffset);
string prefix = Utils.GetXamlNamespacePrefix(CompletionDataHelper.ResolveCompletionContext(context.Editor, context.CompletionChar));
if (!string.IsNullOrEmpty(prefix))
prefix += ":";
@ -96,11 +101,21 @@ namespace ICSharpCode.XamlBinding @@ -96,11 +101,21 @@ namespace ICSharpCode.XamlBinding
XamlCodeCompletionBinding.Instance.CtrlSpace(context.Editor);
}
}
} else {
}
if (item is NewEventCompletionItem) {
NewEventCompletionItem eventItem = item as NewEventCompletionItem;
CreateEventHandlerCode(context, eventItem);
}
if (item is XmlnsCompletionItem) {
context.Editor.Caret.Offset++;
}
if (item is XamlCompletionItem) {
XamlCompletionItem xamlItem = item as XamlCompletionItem;
context.Editor.Document.Insert(context.EndOffset, "=\"\"");
context.Editor.Caret.Offset--;
}
}

22
src/AddIns/BackendBindings/XamlBinding/XamlBinding/XamlContext.cs

@ -5,12 +5,12 @@ @@ -5,12 +5,12 @@
// <version>$Revision: 3731 $</version>
// </file>
using ICSharpCode.SharpDevelop.Editor;
using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Xml;
using ICSharpCode.SharpDevelop;
using ICSharpCode.SharpDevelop.DefaultEditor.Gui.Editor;
using ICSharpCode.SharpDevelop.Dom;
@ -18,18 +18,23 @@ using ICSharpCode.XmlEditor; @@ -18,18 +18,23 @@ using ICSharpCode.XmlEditor;
namespace ICSharpCode.XamlBinding
{
public class XamlContext {
public class XamlContext : ExpressionContext {
public XmlElementPath Path { get; set; }
public string AttributeName { get; set; }
public ResolveResult ResolvedExpression { get; set; }
public AttributeValue AttributeValue { get; set; }
public char PressedKey { get; set; }
public string RawAttributeValue { get; set; }
public int ValueStartOffset { get; set; }
public XamlContextDescription Description { get; set; }
public Dictionary<string, string> XmlnsDefinitions { get; set; }
public ParseInformation ParseInformation { get; set; }
public XamlContext() {}
public override bool ShowEntry(object o)
{
return true;
}
public override string ToString()
{
return "[XamlContext" +
@ -39,10 +44,19 @@ namespace ICSharpCode.XamlBinding @@ -39,10 +44,19 @@ namespace ICSharpCode.XamlBinding
" ValueStartOffset: " + ValueStartOffset +
" ]";
}
}
public class XamlCompletionContext : XamlContext {
public char PressedKey { get; set; }
public bool Forced { get; set; }
public ITextEditor Editor { get; set; }
}
public enum XamlContextDescription {
/// <summary>
/// Outside any tag
/// </summary>
None,
/// <summary>
/// After '&lt;'
/// </summary>

106
src/AddIns/BackendBindings/XamlBinding/XamlBinding/XamlResolver.cs

@ -23,59 +23,70 @@ namespace ICSharpCode.XamlBinding @@ -23,59 +23,70 @@ namespace ICSharpCode.XamlBinding
public class XamlResolver : IResolver
{
IClass callingClass;
string fileContent;
string resolveExpression;
XamlExpressionContext context;
ParseInformation parseInfo;
int caretLineNumber, caretColumn;
internal bool IsReaderAtTarget(XmlTextReader r)
{
if (r.LineNumber > caretLineNumber)
return true;
else if (r.LineNumber == caretLineNumber)
return r.LinePosition >= caretColumn;
else
return false;
}
int caretLine, caretColumn;
XamlContext context;
public ResolveResult Resolve(ExpressionResult expressionResult, ParseInformation parseInfo, string fileContent)
{
this.resolveExpression = expressionResult.Expression;
this.parseInfo = parseInfo;
this.caretLineNumber = expressionResult.Region.BeginLine;
this.caretLine = expressionResult.Region.BeginLine;
this.caretColumn = expressionResult.Region.BeginColumn;
this.callingClass = parseInfo.BestCompilationUnit.GetInnermostClass(caretLineNumber, caretColumn);
this.context = expressionResult.Context as XamlExpressionContext;
if (context == null)
return null;
try {
using (XmlTextReader r = new XmlTextReader(new StringReader(fileContent))) {
r.WhitespaceHandling = WhitespaceHandling.Significant;
// move reader to correct position
while (r.Read() && !IsReaderAtTarget(r)) { }
this.fileContent = fileContent;
this.callingClass = parseInfo.BestCompilationUnit.GetInnermostClass(caretLine, caretColumn);
this.context = expressionResult.Context as XamlContext ?? CompletionDataHelper.ResolveContext(fileContent, parseInfo.MostRecentCompilationUnit.FileName, caretLine, caretColumn);
if (string.IsNullOrEmpty(context.AttributeName)) {
return ResolveElementName(r, expressionResult.Expression);
}
else if (context.InAttributeValue) {
MemberResolveResult mrr = ResolveAttribute(r, context.AttributeName);
switch (this.context.Description) {
case XamlContextDescription.AtTag:
return ResolveElementName(resolveExpression);
case XamlContextDescription.InTag:
return ResolveAttribute(resolveExpression);
case XamlContextDescription.InAttributeValue:
MemberResolveResult mrr = ResolveAttribute(context.AttributeName);
if (mrr != null) {
return ResolveAttributeValue(mrr.ResolvedMember, resolveExpression);
return ResolveAttributeValue(mrr.ResolvedMember, resolveExpression) ?? mrr;
}
break;
case XamlContextDescription.InMarkupExtension:
return ResolveMarkupExtension(resolveExpression);
}
else {
// in attribute name
return ResolveAttribute(r, resolveExpression);
}
return null;
}
ResolveResult ResolveMarkupExtension(string expression)
{
if (context.AttributeValue.IsString)
return null;
object data = Utils.GetMarkupDataAtPosition(context.AttributeValue.ExtensionValue, context.ValueStartOffset);
// resolve markup extension type
if ((data as string) == expression) {
return ResolveElementName(expression + "Extension") ?? ResolveElementName(expression);
} else {
var value = data as AttributeValue;
if (value != null && value.IsString) {
return ResolveElementName(expression) ?? ResolveAttribute(expression);
}
catch (XmlException) {
if (data is KeyValuePair<string, AttributeValue>) {
var pair = (KeyValuePair<string, AttributeValue>)data;
var member = ResolveAttribute(pair.Key);
if (pair.Value.StartOffset + pair.Key.Length >= context.ValueStartOffset) {
return member;
} else {
if (pair.Value.IsString && member != null)
return ResolveAttributeValue(member.ResolvedMember, expression);
}
}
return null;
}
}
ResolveResult ResolveElementName(XmlReader r, string exp)
ResolveResult ResolveElementName(string exp)
{
string xmlNamespace;
string name;
@ -83,10 +94,12 @@ namespace ICSharpCode.XamlBinding @@ -83,10 +94,12 @@ namespace ICSharpCode.XamlBinding
if (resolveExpression.Contains(":")) {
string prefix = resolveExpression.Substring(0, resolveExpression.IndexOf(':'));
name = resolveExpression.Substring(resolveExpression.IndexOf(':') + 1);
xmlNamespace = r.LookupNamespace(prefix);
if (!context.XmlnsDefinitions.TryGetValue(prefix, out xmlNamespace))
xmlNamespace = null;
}
else {
xmlNamespace = r.LookupNamespace("");
if (!context.XmlnsDefinitions.TryGetValue("", out xmlNamespace))
xmlNamespace = null;
name = resolveExpression;
}
if (name.Contains(".")) {
@ -95,7 +108,7 @@ namespace ICSharpCode.XamlBinding @@ -95,7 +108,7 @@ namespace ICSharpCode.XamlBinding
return ResolveProperty(xmlNamespace, name, propertyName, true);
}
else {
IProjectContent pc = parseInfo.BestCompilationUnit.ProjectContent;
IProjectContent pc = context.ParseInformation.BestCompilationUnit.ProjectContent;
IReturnType resolvedType = XamlCompilationUnit.FindType(pc, xmlNamespace, name);
IClass resolvedClass = resolvedType != null ? resolvedType.GetUnderlyingClass() : null;
if (resolvedClass != null) {
@ -109,7 +122,7 @@ namespace ICSharpCode.XamlBinding @@ -109,7 +122,7 @@ namespace ICSharpCode.XamlBinding
MemberResolveResult ResolveProperty(string xmlNamespace, string className, string propertyName, bool allowAttached)
{
IProjectContent pc = parseInfo.BestCompilationUnit.ProjectContent;
IProjectContent pc = context.ParseInformation.BestCompilationUnit.ProjectContent;
IReturnType resolvedType = XamlCompilationUnit.FindType(pc, xmlNamespace, className);
if (resolvedType != null && resolvedType.GetUnderlyingClass() != null) {
IMember member = resolvedType.GetProperties().Find(delegate(IProperty p) { return p.Name == propertyName; });
@ -140,18 +153,21 @@ namespace ICSharpCode.XamlBinding @@ -140,18 +153,21 @@ namespace ICSharpCode.XamlBinding
return null;
}
MemberResolveResult ResolveAttribute(XmlReader r, string attributeName)
MemberResolveResult ResolveAttribute(string attributeName)
{
if (context.ElementPath.Elements.Count == 0) {
if (context.Path == null) {
return null;
}
string attributeXmlNamespace;
if (attributeName.Contains(":")) {
attributeXmlNamespace = r.LookupNamespace(attributeName.Substring(0, attributeName.IndexOf(':')));
string prefix = attributeName.Substring(0, attributeName.IndexOf(':'));
if (!context.XmlnsDefinitions.TryGetValue(prefix, out attributeXmlNamespace))
attributeXmlNamespace = null;
attributeName = attributeName.Substring(attributeName.IndexOf(':') + 1);
}
else {
attributeXmlNamespace = r.LookupNamespace("");
if (!context.XmlnsDefinitions.TryGetValue("", out attributeXmlNamespace))
attributeXmlNamespace = null;
}
if (attributeName.Contains(".")) {
string className = attributeName.Substring(0, attributeName.IndexOf('.'));
@ -159,7 +175,7 @@ namespace ICSharpCode.XamlBinding @@ -159,7 +175,7 @@ namespace ICSharpCode.XamlBinding
return ResolveProperty(attributeXmlNamespace, className, attributeName, true);
}
else {
ICSharpCode.XmlEditor.QualifiedName lastElement = context.ElementPath.Elements[context.ElementPath.Elements.Count - 1];
ICSharpCode.XmlEditor.QualifiedName lastElement = context.Path.Elements.LastOrDefault();
return ResolveProperty(lastElement.Namespace, lastElement.Name, attributeName, false);
}
}

36
src/AddIns/DisplayBindings/AvalonEdit.AddIn/Src/CodeEditor.cs

@ -391,7 +391,7 @@ namespace ICSharpCode.AvalonEdit.AddIn @@ -391,7 +391,7 @@ namespace ICSharpCode.AvalonEdit.AddIn
void OnCodeCompletion(object sender, ExecutedRoutedEventArgs e)
{
CloseExistingCompletionWindows();
CloseExistingCompletionWindow();
TextEditor textEditor = GetTextEditorFromSender(sender);
foreach (ICodeCompletionBinding cc in CodeCompletionBindings) {
if (cc.CtrlSpace(GetAdapter(textEditor))) {
@ -401,39 +401,61 @@ namespace ICSharpCode.AvalonEdit.AddIn @@ -401,39 +401,61 @@ namespace ICSharpCode.AvalonEdit.AddIn
}
}
CompletionWindow completionWindow;
SharpDevelopCompletionWindow completionWindow;
SharpDevelopInsightWindow insightWindow;
void CloseExistingCompletionWindows()
void CloseExistingCompletionWindow()
{
if (completionWindow != null) {
completionWindow.Close();
}
}
void CloseExistingInsightWindow()
{
if (insightWindow != null) {
insightWindow.Close();
}
}
public SharpDevelopCompletionWindow ActiveCompletionWindow {
get { return completionWindow; }
}
public SharpDevelopInsightWindow ActiveInsightWindow {
get { return insightWindow; }
}
internal void NotifyCompletionWindowOpened(CompletionWindow window)
internal void ShowCompletionWindow(SharpDevelopCompletionWindow window)
{
CloseExistingCompletionWindows();
CloseExistingCompletionWindow();
completionWindow = window;
window.Closed += delegate {
completionWindow = null;
};
Dispatcher.BeginInvoke(DispatcherPriority.Normal, new Action(
delegate {
if (completionWindow == window) {
window.Show();
}
}
));
}
internal void NotifyInsightWindowOpened(SharpDevelopInsightWindow window)
internal void ShowInsightWindow(SharpDevelopInsightWindow window)
{
CloseExistingCompletionWindows();
CloseExistingInsightWindow();
insightWindow = window;
window.Closed += delegate {
insightWindow = null;
};
Dispatcher.BeginInvoke(DispatcherPriority.Normal, new Action(
delegate {
if (insightWindow == window) {
window.Show();
}
}
));
}
IFormattingStrategy formattingStrategy;

18
src/AddIns/DisplayBindings/AvalonEdit.AddIn/Src/CodeEditorAdapter.cs

@ -37,13 +37,17 @@ namespace ICSharpCode.AvalonEdit.AddIn @@ -37,13 +37,17 @@ namespace ICSharpCode.AvalonEdit.AddIn
get { return codeEditor.FormattingStrategy; }
}
public override void ShowCompletionWindow(ICompletionItemList data)
public override ICompletionListWindow ActiveCompletionWindow {
get { return codeEditor.ActiveCompletionWindow; }
}
public override ICompletionListWindow ShowCompletionWindow(ICompletionItemList data)
{
if (data == null || !data.Items.Any())
return;
CompletionWindow window = new SharpDevelopCompletionWindow(this, this.TextEditor.TextArea, data);
codeEditor.NotifyCompletionWindowOpened(window);
window.Show();
return null;
SharpDevelopCompletionWindow window = new SharpDevelopCompletionWindow(this, this.TextEditor.TextArea, data);
codeEditor.ShowCompletionWindow(window);
return window;
}
public override IInsightWindow ShowInsightWindow(IEnumerable<IInsightItem> items)
@ -58,9 +62,7 @@ namespace ICSharpCode.AvalonEdit.AddIn @@ -58,9 +62,7 @@ namespace ICSharpCode.AvalonEdit.AddIn
// don't open insight window when there are no items
return null;
}
codeEditor.NotifyInsightWindowOpened(insightWindow);
insightWindow.Show();
codeEditor.ShowInsightWindow(insightWindow);
return insightWindow;
}

45
src/AddIns/DisplayBindings/AvalonEdit.AddIn/Src/SharpDevelopCompletionWindow.cs

@ -5,23 +5,60 @@ @@ -5,23 +5,60 @@
// <version>$Revision$</version>
// </file>
using ICSharpCode.SharpDevelop.Editor.CodeCompletion;
using System;
using System.Linq;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Input;
using System.Windows.Media;
using ICSharpCode.AvalonEdit.CodeCompletion;
using ICSharpCode.AvalonEdit.Document;
using ICSharpCode.AvalonEdit.Editing;
using ICSharpCode.SharpDevelop;
using ICSharpCode.SharpDevelop.Editor;
using ICSharpCode.SharpDevelop.Editor.CodeCompletion;
namespace ICSharpCode.AvalonEdit.AddIn
{
/// <summary>
/// The code completion window.
/// </summary>
public class SharpDevelopCompletionWindow : CompletionWindow
public class SharpDevelopCompletionWindow : CompletionWindow, ICompletionListWindow
{
public ICompletionItem SelectedItem {
get {
return ((CodeCompletionDataAdapter)this.CompletionList.SelectedItem).Item;
}
set {
var itemAdapters = this.CompletionList.CompletionData.Cast<CodeCompletionDataAdapter>();
this.CompletionList.SelectedItem = itemAdapters.FirstOrDefault(a => a.Item == value);
}
}
double ICompletionWindow.Width {
get { return this.Width; }
set {
// Disable virtualization if we use automatic width - this prevents the window from resizing
// when the user scrolls.
VirtualizingStackPanel.SetIsVirtualizing(this.CompletionList.ListBox, !double.IsNaN(value));
this.Width = value;
if (double.IsNaN(value)) {
// enable size-to-width:
if (this.SizeToContent == SizeToContent.Manual)
this.SizeToContent = SizeToContent.Width;
else if (this.SizeToContent == SizeToContent.Height)
this.SizeToContent = SizeToContent.WidthAndHeight;
} else {
// disable size-to-width:
if (this.SizeToContent == SizeToContent.Width)
this.SizeToContent = SizeToContent.Manual;
else if (this.SizeToContent == SizeToContent.WidthAndHeight)
this.SizeToContent = SizeToContent.Height;
}
}
}
readonly ICompletionItemList itemList;
public ICompletionItemList ItemList {
@ -92,6 +129,10 @@ namespace ICSharpCode.AvalonEdit.AddIn @@ -92,6 +129,10 @@ namespace ICSharpCode.AvalonEdit.AddIn
this.item = item;
}
public ICompletionItem Item {
get { return item; }
}
public string Text {
get { return item.Text; }
}

10
src/AddIns/DisplayBindings/XmlEditor/Project/Src/FormatXmlCommand.cs

@ -5,9 +5,10 @@ @@ -5,9 +5,10 @@
// <version>$Revision$</version>
// </file>
using ICSharpCode.SharpDevelop.Gui;
using ICSharpCode.SharpDevelop.Editor;
using System;
using ICSharpCode.Core;
using ICSharpCode.SharpDevelop.Gui;
namespace ICSharpCode.XmlEditor
{
@ -18,11 +19,10 @@ namespace ICSharpCode.XmlEditor @@ -18,11 +19,10 @@ namespace ICSharpCode.XmlEditor
{
public override void Run()
{
// Find active XmlView.
XmlView xmlView = XmlView.ActiveXmlView;
ITextEditorProvider provider = WorkbenchSingleton.Workbench.ActiveViewContent as ITextEditorProvider;
if (xmlView != null) {
xmlView.FormatXml();
if (provider != null) {
XmlView.FormatXml(provider.TextEditor);
}
}
}

60
src/AddIns/DisplayBindings/XmlEditor/Project/Src/XmlCodeCompletionBinding.cs

@ -1,29 +1,28 @@ @@ -1,29 +1,28 @@
// <file>
// <copyright see="prj:///doc/copyright.txt"/>
// <license see="prj:///doc/license.txt"/>
// <owner name="Siegfried Pammer" email="sie_pam@gmx.at"/>
// <owner name="Matthew Ward" email="mrward@users.sourceforge.net"/>
// <version>$Revision$</version>
// </file>
using System;
using System.IO;
using ICSharpCode.Core;
using ICSharpCode.SharpDevelop.Editor;
using ICSharpCode.SharpDevelop.Editor.CodeCompletion;
namespace ICSharpCode.XmlEditor
{
/// <summary>
/// Description of XmlCodeCompletionBinding.
/// </summary>
public class XmlCodeCompletionBinding : ICodeCompletionBinding
{
static XmlCodeCompletionBinding instance;
public static XmlCodeCompletionBinding Instance {
get {
if (instance == null)
if (instance == null) {
instance = new XmlCodeCompletionBinding();
}
return instance;
}
}
@ -34,44 +33,51 @@ namespace ICSharpCode.XmlEditor @@ -34,44 +33,51 @@ namespace ICSharpCode.XmlEditor
public CodeCompletionKeyPressResult HandleKeyPress(ITextEditor editor, char ch)
{
string text = string.Concat(editor.Document.GetText(0, editor.Caret.Offset), ch);
string extension = Path.GetExtension(editor.FileName);
string defaultNamespacePrefix = XmlSchemaManager.GetNamespacePrefix(extension);
XmlSchemaCompletionData defaultSchemaCompletionData = XmlSchemaManager.GetSchemaCompletionData(extension);
XmlCompletionDataProvider provider = new XmlCompletionDataProvider(XmlSchemaManager.SchemaCompletionDataItems,
defaultSchemaCompletionData,
defaultNamespacePrefix);
editor.ShowCompletionWindow(provider.GenerateCompletionData(text, ch));
string text = editor.Document.GetText(0, editor.Caret.Offset);
XmlCompletionDataProvider provider = GetProvider(editor.FileName);
ICompletionItemList completionItems = provider.GenerateCompletionData(text, ch);
ICompletionListWindow completionWindow = editor.ShowCompletionWindow(completionItems);
if (completionWindow != null) {
XmlCompletionItem item = completionItems.SuggestedItem as XmlCompletionItem;
if (item.DataType == XmlCompletionDataType.NamespaceUri) {
completionWindow.Width = double.NaN;
}
}
if (ch == '<' || ch == ' ' || ch == '=')
if ((ch == '<') || (ch == ' ') || (ch == '=')) {
return CodeCompletionKeyPressResult.Completed;
else
}
return CodeCompletionKeyPressResult.CompletedIncludeKeyInCompletion;
}
public bool CtrlSpace(ITextEditor editor)
{
// Attribute value completion.
string text = editor.Document.Text;
int offset = editor.Caret.Offset;
string extension = Path.GetExtension(editor.FileName);
string defaultNamespacePrefix = XmlSchemaManager.GetNamespacePrefix(extension);
XmlSchemaCompletionData defaultSchemaCompletionData = XmlSchemaManager.GetSchemaCompletionData(extension);
XmlCompletionDataProvider provider = new XmlCompletionDataProvider(XmlSchemaManager.SchemaCompletionDataItems,
defaultSchemaCompletionData,
defaultNamespacePrefix);
// Attribute value completion.
if (XmlParser.IsInsideAttributeValue(text, offset)) {
XmlElementPath path = XmlParser.GetActiveElementStartPath(text, offset);
if (path.Elements.Count > 0) {
XmlCompletionDataProvider provider = GetProvider(editor.FileName);
editor.ShowCompletionWindow(provider.GetAttributeValueCompletionData(path, XmlParser.GetAttributeNameAtIndex(text, offset)));
return true;
}
}
return false;
}
public static XmlCompletionDataProvider GetProvider(string fileName)
{
string extension = Path.GetExtension(fileName);
if (PropertyService.DataDirectory != null) {
XmlSchemaCompletionDataCollection schemas = XmlSchemaManager.SchemaCompletionDataItems;
string defaultNamespacePrefix = XmlSchemaManager.GetNamespacePrefix(extension);
XmlSchemaCompletionData defaultSchemaCompletionData = XmlSchemaManager.GetSchemaCompletionData(extension);
return new XmlCompletionDataProvider(schemas, defaultSchemaCompletionData, defaultNamespacePrefix);
}
// for unit tests
return new XmlCompletionDataProvider(new XmlSchemaCompletionDataCollection(), null, String.Empty);
}
}
}

4
src/AddIns/DisplayBindings/XmlEditor/Project/Src/XmlCompletionDataProvider.cs

@ -141,7 +141,7 @@ namespace ICSharpCode.XmlEditor @@ -141,7 +141,7 @@ namespace ICSharpCode.XmlEditor
public DefaultCompletionItemList GetAttributeCompletionData(XmlElementPath path)
{
var list = new XmlCompletionItemList();
XmlCompletionItemList list = new XmlCompletionItemList();
XmlSchemaCompletionData schema = FindSchema(path);
if (schema != null) {
@ -155,7 +155,7 @@ namespace ICSharpCode.XmlEditor @@ -155,7 +155,7 @@ namespace ICSharpCode.XmlEditor
public DefaultCompletionItemList GetAttributeValueCompletionData(XmlElementPath path, string name)
{
var list = new XmlCompletionItemList();
XmlCompletionItemList list = new XmlCompletionItemList();
XmlSchemaCompletionData schema = FindSchema(path);
if (schema != null) {

15
src/AddIns/DisplayBindings/XmlEditor/Project/Src/XmlCompletionItem.cs

@ -28,10 +28,10 @@ namespace ICSharpCode.XmlEditor @@ -28,10 +28,10 @@ namespace ICSharpCode.XmlEditor
public class XmlCompletionItem : DefaultCompletionItem
{
XmlCompletionDataType dataType = XmlCompletionDataType.XmlElement;
string description = string.Empty;
string description = String.Empty;
public XmlCompletionItem(string text)
: this(text, string.Empty, XmlCompletionDataType.XmlElement)
: this(text, String.Empty, XmlCompletionDataType.XmlElement)
{
}
@ -41,7 +41,7 @@ namespace ICSharpCode.XmlEditor @@ -41,7 +41,7 @@ namespace ICSharpCode.XmlEditor
}
public XmlCompletionItem(string text, XmlCompletionDataType dataType)
: this(text, string.Empty, dataType)
: this(text, String.Empty, dataType)
{
}
@ -57,9 +57,11 @@ namespace ICSharpCode.XmlEditor @@ -57,9 +57,11 @@ namespace ICSharpCode.XmlEditor
/// the xs:annotation/xs:documentation element.
/// </summary>
public override string Description {
get {
return description;
get { return description; }
}
public XmlCompletionDataType DataType {
get { return dataType; }
}
public override void Complete(CompletionContext context)
@ -69,7 +71,7 @@ namespace ICSharpCode.XmlEditor @@ -69,7 +71,7 @@ namespace ICSharpCode.XmlEditor
switch (dataType) {
case XmlCompletionDataType.NamespaceUri:
context.Editor.Document.Insert(context.StartOffset, "\"");
context.Editor.Document.Insert(context.EndOffset, "\"");
context.Editor.Document.Insert(context.EndOffset + 1, "\"");
break;
case XmlCompletionDataType.XmlAttribute:
context.Editor.Document.Insert(context.EndOffset, "=\"\"");
@ -83,6 +85,5 @@ namespace ICSharpCode.XmlEditor @@ -83,6 +85,5 @@ namespace ICSharpCode.XmlEditor
{
return "[" + this.Text + "]";
}
}
}

37
src/AddIns/DisplayBindings/XmlEditor/Project/Src/XmlFormattingStrategy.cs

@ -5,14 +5,16 @@ @@ -5,14 +5,16 @@
// <version>$Revision$</version>
// </file>
using ICSharpCode.SharpDevelop.Editor;
using System;
using System.Collections;
using System.Collections.Generic;
using System.Diagnostics;
using System.IO;
using System.Linq;
using System.Text;
using System.Xml;
using ICSharpCode.Core;
using ICSharpCode.SharpDevelop.Editor;
namespace ICSharpCode.XmlEditor
{
@ -52,7 +54,9 @@ namespace ICSharpCode.XmlEditor @@ -52,7 +54,9 @@ namespace ICSharpCode.XmlEditor
}
string tagString = tag.ToString();
if (tagString.Length > 0 && !tagString.StartsWith("!", StringComparison.Ordinal) && !tagString.StartsWith("?", StringComparison.Ordinal)) {
int caretOffset = editor.Caret.Offset;
editor.Document.Insert(editor.Caret.Offset, "</" + tagString + ">");
editor.Caret.Offset = caretOffset;
}
}
}
@ -66,7 +70,7 @@ namespace ICSharpCode.XmlEditor @@ -66,7 +70,7 @@ namespace ICSharpCode.XmlEditor
Debug.Assert(false, e.ToString());
}
if (charTyped == '\n') {
IndentLine(editor, editor.Document.GetLineForOffset(editor.Caret.Offset));
IndentLine(editor, editor.Document.GetLine(editor.Caret.Line));
}
editor.Document.EndUndoableAction();
}
@ -97,11 +101,11 @@ namespace ICSharpCode.XmlEditor @@ -97,11 +101,11 @@ namespace ICSharpCode.XmlEditor
editor.Document.EndUndoableAction();
}
}
#region Smart Indentation
static void TryIndent(ITextEditor editor, int begin, int end)
{
string currentIndentation = "";
Stack tagStack = new Stack();
Stack<string> tagStack = new Stack<string>();
IDocument document = editor.Document;
string tab = editor.Options.IndentationString;
int nextLine = begin; // in #dev coordinates
@ -116,16 +120,16 @@ namespace ICSharpCode.XmlEditor @@ -116,16 +120,16 @@ namespace ICSharpCode.XmlEditor
if (tagStack.Count == 0)
currentIndentation = "";
else
currentIndentation = (string)tagStack.Pop();
currentIndentation = tagStack.Pop();
}
if (r.NodeType == XmlNodeType.EndElement) {
if (tagStack.Count == 0)
currentIndentation = "";
else
currentIndentation = (string)tagStack.Pop();
currentIndentation = tagStack.Pop();
}
while (r.LineNumber >= nextLine) { // caution: here we compare 1-based and 0-based line numbers
while (r.LineNumber > nextLine) { // caution: here we compare 1-based and 0-based line numbers
if (nextLine > end) break;
if (lastType == XmlNodeType.CDATA || lastType == XmlNodeType.Comment) {
nextLine++;
@ -138,7 +142,7 @@ namespace ICSharpCode.XmlEditor @@ -138,7 +142,7 @@ namespace ICSharpCode.XmlEditor
string newText;
// special case: opening tag has closing bracket on extra line: remove one indentation level
if (lineText.Trim() == ">")
newText = (string)tagStack.Peek() + lineText.Trim();
newText = tagStack.Peek() + lineText.Trim();
else
newText = currentIndentation + lineText.Trim();
@ -154,9 +158,9 @@ namespace ICSharpCode.XmlEditor @@ -154,9 +158,9 @@ namespace ICSharpCode.XmlEditor
if (r.NodeType == XmlNodeType.Element) {
tagStack.Push(currentIndentation);
if (r.LineNumber < begin)
currentIndentation = DocumentUtilitites.GetIndentation(editor.Document, r.LineNumber - 1);
currentIndentation = DocumentUtilitites.GetIndentation(editor.Document, editor.Document.PositionToOffset(r.LineNumber, 1));
if (r.Name.Length < 16)
attribIndent = currentIndentation + new String(' ', 2 + r.Name.Length);
attribIndent = currentIndentation + new string(' ', 2 + r.Name.Length);
else
attribIndent = currentIndentation + tab;
currentIndentation += tab;
@ -168,15 +172,12 @@ namespace ICSharpCode.XmlEditor @@ -168,15 +172,12 @@ namespace ICSharpCode.XmlEditor
if (r.LineNumber != startLine)
attribIndent = currentIndentation; // change to tab-indentation
r.MoveToAttribute(r.AttributeCount - 1);
while (r.LineNumber >= nextLine) {
while (r.LineNumber > nextLine) {
if (nextLine > end) break;
// set indentation of 'nextLine'
IDocumentLine line = document.GetLine(nextLine);
string lineText = line.Text;
string newText = attribIndent + lineText.Trim();
if (newText != lineText) {
document.Replace(line.Offset, line.Length, newText);
}
string newText = attribIndent + line.Text.Trim();
document.SmartReplaceLine(line, newText);
nextLine++;
}
}
@ -184,6 +185,6 @@ namespace ICSharpCode.XmlEditor @@ -184,6 +185,6 @@ namespace ICSharpCode.XmlEditor
r.Close();
}
}
#endregion
}
}

21
src/AddIns/DisplayBindings/XmlEditor/Project/Src/XmlParser.cs

@ -243,12 +243,15 @@ namespace ICSharpCode.XmlEditor @@ -243,12 +243,15 @@ namespace ICSharpCode.XmlEditor
}
// Find equals sign.
bool foundQuoteChar = false;
for (int i = index; i > elementStartIndex; --i) {
char ch = xml[i];
if (ch == '=') {
if (ch == '=' && foundQuoteChar) {
index = i;
ignoreEqualsSign = true;
break;
} else if (IsQuoteChar(ch)) {
foundQuoteChar = true;
}
}
} else {
@ -364,11 +367,14 @@ namespace ICSharpCode.XmlEditor @@ -364,11 +367,14 @@ namespace ICSharpCode.XmlEditor
// Find equals sign.
int equalsSignIndex = -1;
bool foundQuoteChar = false;
for (int i = index; i > elementStartIndex; --i) {
char ch = xml[i];
if (ch == '=') {
if (ch == '=' && foundQuoteChar) {
equalsSignIndex = i;
break;
} else if (IsQuoteChar(ch)) {
foundQuoteChar = true;
}
}
@ -378,12 +384,12 @@ namespace ICSharpCode.XmlEditor @@ -378,12 +384,12 @@ namespace ICSharpCode.XmlEditor
// Find attribute value.
char quoteChar = ' ';
bool foundQuoteChar = false;
foundQuoteChar = false;
StringBuilder attributeValue = new StringBuilder();
for (int i = equalsSignIndex; i < xml.Length; ++i) {
char ch = xml[i];
if (!foundQuoteChar) {
if (ch == '\"' || ch == '\'') {
if (IsQuoteChar(ch)) {
quoteChar = ch;
foundQuoteChar = true;
}
@ -391,7 +397,7 @@ namespace ICSharpCode.XmlEditor @@ -391,7 +397,7 @@ namespace ICSharpCode.XmlEditor
if (ch == quoteChar) {
// End of attribute value.
return attributeValue.ToString();
} else if (IsAttributeValueChar(ch) || (ch == '\"' || ch == '\'')) {
} else if (IsAttributeValueChar(ch) || IsQuoteChar(ch)) {
attributeValue.Append(ch);
} else {
// Invalid character found.
@ -783,5 +789,10 @@ namespace ICSharpCode.XmlEditor @@ -783,5 +789,10 @@ namespace ICSharpCode.XmlEditor
}
return new XmlElementPath();
}
static bool IsQuoteChar(char ch)
{
return (ch == '\"') || (ch == '\'');
}
}
}

6
src/AddIns/DisplayBindings/XmlEditor/Project/Src/XmlTreeView.cs

@ -134,10 +134,10 @@ namespace ICSharpCode.XmlEditor @@ -134,10 +134,10 @@ namespace ICSharpCode.XmlEditor
protected override void LoadFromPrimary()
{
IFileDocumentProvider provider = this.PrimaryViewContent as IFileDocumentProvider;
treeViewContainer.LoadXml(provider.GetDocumentForFile(this.PrimaryFile).Text, XmlView.GetProvider(Path.GetExtension(this.PrimaryFileName)));
treeViewContainer.LoadXml(provider.GetDocumentForFile(this.PrimaryFile).Text, XmlCodeCompletionBinding.GetProvider(Path.GetExtension(this.PrimaryFileName)));
XmlView view = XmlView.ForFile(this.PrimaryFile);
if (view != null) {
view.CheckIsWellFormed();
XmlView.CheckIsWellFormed(view.TextEditor);
}
}
@ -147,7 +147,7 @@ namespace ICSharpCode.XmlEditor @@ -147,7 +147,7 @@ namespace ICSharpCode.XmlEditor
if (!treeViewContainer.IsErrorMessageTextBoxVisible && treeViewContainer.IsDirty) {
XmlView view = XmlView.ForFile(this.PrimaryFile);
if (view != null) {
view.ReplaceAll(treeViewContainer.Document.OuterXml);
XmlView.ReplaceAll(treeViewContainer.Document.OuterXml, view.TextEditor);
ignoreDirtyChange = true;
treeViewContainer.IsDirty = false;
ignoreDirtyChange = false;

116
src/AddIns/DisplayBindings/XmlEditor/Project/Src/XmlView.cs

@ -1,7 +1,7 @@ @@ -1,7 +1,7 @@
// <file>
// <copyright see="prj:///doc/copyright.txt"/>
// <license see="prj:///doc/license.txt"/>
// <owner name="Siegfried Pammer" email="sie_pam@gmx.at"/>
// <owner name="Matthew Ward" email="mrward@users.sourceforge.net"/>
// <version>$Revision$</version>
// </file>
@ -59,44 +59,24 @@ namespace ICSharpCode.XmlEditor @@ -59,44 +59,24 @@ namespace ICSharpCode.XmlEditor
public static XmlView ForViewContent(IViewContent view)
{
if (view == null || view.PrimaryFile == null)
if ((view == null) || (view.PrimaryFile == null)) {
return null;
}
return ForFile(view.PrimaryFile);
}
static void FileClosedHandler(object sender, EventArgs e)
{
if (sender is OpenedFile)
if (sender is OpenedFile) {
mapping.Remove(sender as OpenedFile);
}
}
public string StylesheetFileName { get; set; }
public XmlCompletionDataProvider GetProvider()
{
return GetProvider(Path.GetExtension(File.FileName));
}
public static XmlCompletionDataProvider GetProvider(string extension)
{
string defaultNamespacePrefix;
XmlSchemaCompletionData defaultSchemaCompletionData;
XmlSchemaCompletionDataCollection schemas;
if (PropertyService.DataDirectory != null) {
schemas = XmlSchemaManager.SchemaCompletionDataItems;
defaultNamespacePrefix = XmlSchemaManager.GetNamespacePrefix(extension);
defaultSchemaCompletionData = XmlSchemaManager.GetSchemaCompletionData(extension);
} else {
// for NUnit tests
defaultNamespacePrefix = string.Empty;
schemas = new XmlSchemaCompletionDataCollection();
defaultSchemaCompletionData = null;
}
return new XmlCompletionDataProvider(schemas,
defaultSchemaCompletionData,
defaultNamespacePrefix);
return XmlCodeCompletionBinding.GetProvider(Path.GetExtension(File.FileName));
}
public ITextEditor TextEditor
@ -104,14 +84,13 @@ namespace ICSharpCode.XmlEditor @@ -104,14 +84,13 @@ namespace ICSharpCode.XmlEditor
get {
foreach (IViewContent view in File.RegisteredViewContents) {
ITextEditorProvider provider = view as ITextEditorProvider;
if (provider != null) {
IDocument document = provider.GetDocumentForFile(File);
if (document != null)
if (document != null) {
return provider.TextEditor;
}
}
}
return null;
}
}
@ -121,18 +100,16 @@ namespace ICSharpCode.XmlEditor @@ -121,18 +100,16 @@ namespace ICSharpCode.XmlEditor
get {
foreach (IViewContent view in File.RegisteredViewContents) {
XmlTreeView tree = view as XmlTreeView;
if (tree != null)
if (tree != null) {
return tree;
}
}
return null;
}
}
public static XmlView ActiveXmlView {
get {
return XmlView.ForViewContent(WorkbenchSingleton.Workbench.ActiveViewContent);
}
get { return XmlView.ForViewContent(WorkbenchSingleton.Workbench.ActiveViewContent); }
}
/// <summary>
@ -207,24 +184,24 @@ namespace ICSharpCode.XmlEditor @@ -207,24 +184,24 @@ namespace ICSharpCode.XmlEditor
/// Checks that the xml in this view is well-formed.
/// </summary>
public bool IsWellFormed {
get {
return CheckIsWellFormed();
}
get { return CheckIsWellFormed(); }
}
public bool CheckIsWellFormed()
{
ITextEditor editor = TextEditor;
return CheckIsWellFormed(TextEditor);
}
public static bool CheckIsWellFormed(ITextEditor editor)
{
if (editor == null) return false;
try {
XmlDocument Document = new XmlDocument();
Document.LoadXml(editor.Document.Text);
return true;
}
catch (XmlException ex) {
} catch (XmlException ex) {
AddTask(editor.FileName, ex.Message, ex.LinePosition - 1, ex.LineNumber - 1, TaskType.Error);
}
catch (WebException ex) {
} catch (WebException ex) {
AddTask(editor.FileName, ex.Message, 0, 0, TaskType.Error);
}
return false;
@ -435,8 +412,7 @@ namespace ICSharpCode.XmlEditor @@ -435,8 +412,7 @@ namespace ICSharpCode.XmlEditor
public string[] InferSchema()
{
ITextEditor editor = TextEditor;
if (editor == null)
return null;
if (editor == null) return null;
TaskService.ClearExceptCommentTasks();
if (IsWellFormed) {
@ -457,16 +433,13 @@ namespace ICSharpCode.XmlEditor @@ -457,16 +433,13 @@ namespace ICSharpCode.XmlEditor
/// <summary>
/// Pretty prints the xml.
/// </summary>
public void FormatXml()
public static void FormatXml(ITextEditor editor)
{
ITextEditor editor = TextEditor;
if (editor == null)
return;
if (editor == null) return;
TaskService.ClearExceptCommentTasks();
if (IsWellFormed) {
ReplaceAll(editor.Document.Text);
if (CheckIsWellFormed(editor)) {
ReplaceAll(editor.Document.Text, editor);
} else {
ShowErrorList();
}
@ -476,13 +449,11 @@ namespace ICSharpCode.XmlEditor @@ -476,13 +449,11 @@ namespace ICSharpCode.XmlEditor
/// Replaces the entire text of the xml view with the xml in the
/// specified. The xml will be formatted.
/// </summary>
public void ReplaceAll(string xml)
public static void ReplaceAll(string xml, ITextEditor editor)
{
ITextEditor editor = TextEditor;
if (editor == null)
return;
if (editor == null) return;
string formattedXml = SimpleFormat(IndentedFormat(xml));
string formattedXml = SimpleFormat(IndentedFormat(xml, editor));
editor.Document.Text = formattedXml;
//UpdateFolding(); // TODO : add again when folding is implemented in AvalonEdit
}
@ -502,17 +473,15 @@ namespace ICSharpCode.XmlEditor @@ -502,17 +473,15 @@ namespace ICSharpCode.XmlEditor
/// <returns>A pretty print version of the specified xml. If the
/// string is not well formed xml the original string is returned.
/// </returns>
string IndentedFormat(string xml)
static string IndentedFormat(string xml, ITextEditor editor)
{
string indentedText = string.Empty;
ITextEditor editor = TextEditor;
if (editor == null)
return indentedText;
if (editor == null) return indentedText;
try {
XmlTextReader reader = new XmlTextReader(new StringReader(xml));
reader.WhitespaceHandling = WhitespaceHandling.None;
reader.XmlResolver = null;
StringWriter indentedXmlWriter = new StringWriter();
XmlTextWriter writer = CreateXmlTextWriter(indentedXmlWriter, editor);
@ -523,7 +492,6 @@ namespace ICSharpCode.XmlEditor @@ -523,7 +492,6 @@ namespace ICSharpCode.XmlEditor
} catch(Exception) {
indentedText = xml;
}
return indentedText;
}
@ -539,14 +507,14 @@ namespace ICSharpCode.XmlEditor @@ -539,14 +507,14 @@ namespace ICSharpCode.XmlEditor
OutputWindowWriteLine(StringParser.Parse("${res:MainWindow.XmlValidationMessages.ValidationStarted}"));
if (IsSchema) {
if (!ValidateSchema())
if (!ValidateSchema()) {
return;
} else {
if (!ValidateAgainstSchema())
}
} else if (!ValidateAgainstSchema()) {
return;
}
OutputWindowWriteLine(string.Empty);
OutputWindowWriteLine(String.Empty);
OutputWindowWriteLine(StringParser.Parse("${res:MainWindow.XmlValidationMessages.ValidationSuccess}"));
}
@ -554,7 +522,7 @@ namespace ICSharpCode.XmlEditor @@ -554,7 +522,7 @@ namespace ICSharpCode.XmlEditor
get {
string extension = Path.GetExtension(File.FileName);
if (extension != null) {
return string.Compare(".xsd", extension, StringComparison.OrdinalIgnoreCase) == 0;
return String.Compare(".xsd", extension, StringComparison.OrdinalIgnoreCase) == 0;
}
return false;
}
@ -567,8 +535,7 @@ namespace ICSharpCode.XmlEditor @@ -567,8 +535,7 @@ namespace ICSharpCode.XmlEditor
bool ValidateAgainstSchema()
{
ITextEditor editor = TextEditor;
if (editor == null)
return false;
if (editor == null) return false;
try {
StringReader stringReader = new StringReader(editor.Document.Text);
@ -616,8 +583,7 @@ namespace ICSharpCode.XmlEditor @@ -616,8 +583,7 @@ namespace ICSharpCode.XmlEditor
bool ValidateSchema()
{
ITextEditor editor = TextEditor;
if (editor == null)
return false;
if (editor == null) return false;
StringReader stringReader = new StringReader(editor.Document.Text);
XmlTextReader xmlReader = new XmlTextReader(stringReader);
@ -685,8 +651,7 @@ namespace ICSharpCode.XmlEditor @@ -685,8 +651,7 @@ namespace ICSharpCode.XmlEditor
TaskService.ClearExceptCommentTasks();
ITextEditor editor = TextEditor;
if (editor == null)
return;
if (editor == null) return;
if (IsWellFormed) {
if (IsValidXsl(xsl)) {
@ -711,7 +676,7 @@ namespace ICSharpCode.XmlEditor @@ -711,7 +676,7 @@ namespace ICSharpCode.XmlEditor
void ShowTransformOutput(string xml)
{
// Pretty print the xml.
xml = SimpleFormat(IndentedFormat(xml));
xml = SimpleFormat(IndentedFormat(xml, TextEditor));
// Display the output xml.
XslOutputView.EditorInstance.Document.Text = xml;
@ -818,9 +783,6 @@ namespace ICSharpCode.XmlEditor @@ -818,9 +783,6 @@ namespace ICSharpCode.XmlEditor
/// <summary>
/// Tries to get the filename from the inner exception otherwise returns the default filename.
/// </summary>
/// <param name="ex"></param>
/// <param name="defaultFileName"></param>
/// <returns></returns>
static string GetFileNameFromInnerException(Exception ex, string defaultFileName)
{
XmlException innerException = ex.InnerException as XmlException;

5
src/AddIns/DisplayBindings/XmlEditor/Project/XmlEditor.csproj

@ -166,6 +166,11 @@ @@ -166,6 +166,11 @@
<Name>ICSharpCode.AvalonEdit</Name>
<Private>False</Private>
</ProjectReference>
<ProjectReference Include="..\..\..\..\Libraries\NRefactory\Project\NRefactory.csproj">
<Project>{3A9AE6AA-BC07-4A2F-972C-581E3AE2F195}</Project>
<Name>NRefactory</Name>
<Private>False</Private>
</ProjectReference>
<ProjectReference Include="..\..\..\..\Main\Base\Project\ICSharpCode.SharpDevelop.csproj">
<Project>{2748AD25-9C63-4E12-877B-4DCE96FBED54}</Project>
<Name>ICSharpCode.SharpDevelop</Name>

2
src/AddIns/DisplayBindings/XmlEditor/Test/Parser/AttributeValueUnderCursorTests.cs

@ -85,6 +85,8 @@ namespace XmlEditor.Tests.Parser @@ -85,6 +85,8 @@ namespace XmlEditor.Tests.Parser
string xaml = "<Test val1=\"{Binding Value, Path=Control}\" />";
int offset = "<Test val1=\"{Binding Value, Path=".Length;
Assert.IsTrue(XmlParser.IsInsideAttributeValue(xaml, offset));
Assert.AreEqual("{Binding Value, Path=Control}", XmlParser.GetAttributeValueAtIndex(xaml, offset));
Assert.AreEqual("val1", XmlParser.GetAttributeNameAtIndex(xaml, offset));
}
[Test]

66
src/AddIns/DisplayBindings/XmlEditor/XmlEditor.sln

@ -0,0 +1,66 @@ @@ -0,0 +1,66 @@

Microsoft Visual Studio Solution File, Format Version 10.00
# Visual Studio 2008
# SharpDevelop 3.0.0.3800
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "XmlEditor", "Project\XmlEditor.csproj", "{DCA2703D-250A-463E-A68A-07ED105AE6BD}"
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "XmlEditor.Tests", "Test\XmlEditor.Tests.csproj", "{FC0FE702-A87D-4D70-A9B6-1ECCD611125F}"
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "ICSharpCode.AvalonEdit", "..\..\..\Libraries\AvalonEdit\ICSharpCode.AvalonEdit\ICSharpCode.AvalonEdit.csproj", "{6C55B776-26D4-4DB3-A6AB-87E783B2F3D1}"
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "ICSharpCode.Core", "..\..\..\Main\Core\Project\ICSharpCode.Core.csproj", "{35CEF10F-2D4C-45F2-9DD1-161E0FEC583C}"
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "ICSharpCode.SharpDevelop", "..\..\..\Main\Base\Project\ICSharpCode.SharpDevelop.csproj", "{2748AD25-9C63-4E12-877B-4DCE96FBED54}"
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "ICSharpCode.Core.Presentation", "..\..\..\Main\ICSharpCode.Core.Presentation\ICSharpCode.Core.Presentation.csproj", "{7E4A7172-7FF5-48D0-B719-7CD959DD1AC9}"
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "ICSharpCode.Core.WinForms", "..\..\..\Main\ICSharpCode.Core.WinForms\ICSharpCode.Core.WinForms.csproj", "{857CA1A3-FC88-4BE0-AB6A-D1EE772AB288}"
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "ICSharpCode.SharpDevelop.Dom", "..\..\..\Main\ICSharpCode.SharpDevelop.Dom\Project\ICSharpCode.SharpDevelop.Dom.csproj", "{924EE450-603D-49C1-A8E5-4AFAA31CE6F3}"
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "ICSharpCode.TextEditor", "..\..\..\Libraries\ICSharpCode.TextEditor\Project\ICSharpCode.TextEditor.csproj", "{2D18BE89-D210-49EB-A9DD-2246FBB3DF6D}"
EndProject
Global
GlobalSection(SolutionConfigurationPlatforms) = preSolution
Debug|Any CPU = Debug|Any CPU
Release|Any CPU = Release|Any CPU
EndGlobalSection
GlobalSection(ProjectConfigurationPlatforms) = postSolution
{DCA2703D-250A-463E-A68A-07ED105AE6BD}.Debug|Any CPU.Build.0 = Debug|Any CPU
{DCA2703D-250A-463E-A68A-07ED105AE6BD}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{DCA2703D-250A-463E-A68A-07ED105AE6BD}.Release|Any CPU.Build.0 = Release|Any CPU
{DCA2703D-250A-463E-A68A-07ED105AE6BD}.Release|Any CPU.ActiveCfg = Release|Any CPU
{FC0FE702-A87D-4D70-A9B6-1ECCD611125F}.Debug|Any CPU.Build.0 = Debug|Any CPU
{FC0FE702-A87D-4D70-A9B6-1ECCD611125F}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{FC0FE702-A87D-4D70-A9B6-1ECCD611125F}.Release|Any CPU.Build.0 = Release|Any CPU
{FC0FE702-A87D-4D70-A9B6-1ECCD611125F}.Release|Any CPU.ActiveCfg = Release|Any CPU
{6C55B776-26D4-4DB3-A6AB-87E783B2F3D1}.Debug|Any CPU.Build.0 = Debug|Any CPU
{6C55B776-26D4-4DB3-A6AB-87E783B2F3D1}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{6C55B776-26D4-4DB3-A6AB-87E783B2F3D1}.Release|Any CPU.Build.0 = Release|Any CPU
{6C55B776-26D4-4DB3-A6AB-87E783B2F3D1}.Release|Any CPU.ActiveCfg = Release|Any CPU
{35CEF10F-2D4C-45F2-9DD1-161E0FEC583C}.Debug|Any CPU.Build.0 = Debug|Any CPU
{35CEF10F-2D4C-45F2-9DD1-161E0FEC583C}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{35CEF10F-2D4C-45F2-9DD1-161E0FEC583C}.Release|Any CPU.Build.0 = Release|Any CPU
{35CEF10F-2D4C-45F2-9DD1-161E0FEC583C}.Release|Any CPU.ActiveCfg = Release|Any CPU
{2748AD25-9C63-4E12-877B-4DCE96FBED54}.Debug|Any CPU.Build.0 = Debug|Any CPU
{2748AD25-9C63-4E12-877B-4DCE96FBED54}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{2748AD25-9C63-4E12-877B-4DCE96FBED54}.Release|Any CPU.Build.0 = Release|Any CPU
{2748AD25-9C63-4E12-877B-4DCE96FBED54}.Release|Any CPU.ActiveCfg = Release|Any CPU
{7E4A7172-7FF5-48D0-B719-7CD959DD1AC9}.Debug|Any CPU.Build.0 = Debug|Any CPU
{7E4A7172-7FF5-48D0-B719-7CD959DD1AC9}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{7E4A7172-7FF5-48D0-B719-7CD959DD1AC9}.Release|Any CPU.Build.0 = Release|Any CPU
{7E4A7172-7FF5-48D0-B719-7CD959DD1AC9}.Release|Any CPU.ActiveCfg = Release|Any CPU
{857CA1A3-FC88-4BE0-AB6A-D1EE772AB288}.Debug|Any CPU.Build.0 = Debug|Any CPU
{857CA1A3-FC88-4BE0-AB6A-D1EE772AB288}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{857CA1A3-FC88-4BE0-AB6A-D1EE772AB288}.Release|Any CPU.Build.0 = Release|Any CPU
{857CA1A3-FC88-4BE0-AB6A-D1EE772AB288}.Release|Any CPU.ActiveCfg = Release|Any CPU
{924EE450-603D-49C1-A8E5-4AFAA31CE6F3}.Debug|Any CPU.Build.0 = Debug|Any CPU
{924EE450-603D-49C1-A8E5-4AFAA31CE6F3}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{924EE450-603D-49C1-A8E5-4AFAA31CE6F3}.Release|Any CPU.Build.0 = Release|Any CPU
{924EE450-603D-49C1-A8E5-4AFAA31CE6F3}.Release|Any CPU.ActiveCfg = Release|Any CPU
{2D18BE89-D210-49EB-A9DD-2246FBB3DF6D}.Debug|Any CPU.Build.0 = Debug|Any CPU
{2D18BE89-D210-49EB-A9DD-2246FBB3DF6D}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{2D18BE89-D210-49EB-A9DD-2246FBB3DF6D}.Release|Any CPU.Build.0 = Release|Any CPU
{2D18BE89-D210-49EB-A9DD-2246FBB3DF6D}.Release|Any CPU.ActiveCfg = Release|Any CPU
EndGlobalSection
EndGlobal

19
src/AddIns/Misc/Debugger/Debugger.AddIn/Project/Debugger.AddIn.csproj

@ -170,24 +170,31 @@ @@ -170,24 +170,31 @@
<Compile Include="Src\Visualizers\Graph\DebuggerVisualizerException.cs" />
<Compile Include="Src\Visualizers\Graph\Drawing\CanvasLocationAdapter.cs" />
<Compile Include="Src\Visualizers\Graph\Drawing\GraphDrawer.cs" />
<Compile Include="Src\Visualizers\Graph\Drawing\NodeControl.xaml.cs" />
<Compile Include="Src\Visualizers\Graph\Drawing\NodeControl.xaml.cs">
<DependentUpon>NodeControl.xaml</DependentUpon>
</Compile>
<Compile Include="Src\Visualizers\Graph\ExpandedNodes.cs" />
<Compile Include="Src\Visualizers\Graph\Layout\GraphDiff.cs" />
<Compile Include="Src\Visualizers\Graph\Layout\GraphMatcher.cs" />
<Compile Include="Src\Visualizers\Graph\Layout\PositionedEdge.cs" />
<Compile Include="Src\Visualizers\Graph\Layout\PositionedGraph.cs" />
<Compile Include="Src\Visualizers\Graph\Layout\PositionedNode.cs" />
<Compile Include="Src\Visualizers\Graph\Layout\Tree\DotGraph.cs" />
<Compile Include="Src\Visualizers\Graph\Layout\PositionedNodeProperty.cs" />
<Compile Include="Src\Visualizers\Graph\Layout\PositionedPropertyEventArgs.cs" />
<Compile Include="Src\Visualizers\Graph\Layout\Tree\BoxDotFormatter.cs" />
<Compile Include="Src\Visualizers\Graph\Layout\Tree\DotFormatter.cs" />
<Compile Include="Src\Visualizers\Graph\Layout\Tree\IdGenerator.cs" />
<Compile Include="Src\Visualizers\Graph\Layout\Tree\LayoutDirection.cs" />
<Compile Include="Src\Visualizers\Graph\Layout\Tree\NeatoDoubleFormatter.cs" />
<Compile Include="Src\Visualizers\Graph\Layout\Tree\NeatoEdgeRouter.cs" />
<Compile Include="Src\Visualizers\Graph\Layout\Tree\NeatoPositionTransform.cs" />
<Compile Include="Src\Visualizers\Graph\Layout\Tree\NeatoProcess.cs" />
<Compile Include="Src\Visualizers\Graph\Layout\Tree\RecordDotFormatter.cs" />
<Compile Include="Src\Visualizers\Graph\Layout\Tree\TreeEdge.cs" />
<Compile Include="Src\Visualizers\Graph\Layout\Tree\TreeLayouter.cs" />
<Compile Include="Src\Visualizers\Graph\Layout\Tree\TreeNode.cs" />
<Compile Include="Src\Visualizers\Graph\Layout\Tree\TreeNodeLR.cs" />
<Compile Include="Src\Visualizers\Graph\Layout\Tree\TreeNodeTB.cs" />
<Compile Include="Src\Visualizers\Graph\ObjectGraphVisualizerViewContent.cs" />
<Compile Include="Src\Visualizers\Graph\ObjectGraph\NamedEdge.cs" />
<Compile Include="Src\Visualizers\Graph\ObjectGraph\ObjectEdge.cs" />
<Compile Include="Src\Visualizers\Graph\ObjectGraph\ObjectGraph.cs" />
@ -199,11 +206,6 @@ @@ -199,11 +206,6 @@
<Compile Include="Src\Visualizers\Graph\Utils\DictionaryExtensions.cs" />
<Compile Include="Src\Visualizers\Graph\Utils\Lookup.cs" />
<Compile Include="Src\Visualizers\Graph\Utils\LookupValueCollection.cs" />
<Compile Include="Src\Visualizers\Graph\VisualizerWinFormsControl.cs" />
<Compile Include="Src\Visualizers\Graph\VisualizerWinFormsControl.Designer.cs" />
<Compile Include="Src\Visualizers\Graph\VisualizerWPFControl.xaml.cs">
<DependentUpon>VisualizerWPFControl.xaml</DependentUpon>
</Compile>
<Compile Include="Src\Visualizers\Graph\VisualizerWPFWindow.xaml.cs">
<DependentUpon>VisualizerWPFWindow.xaml</DependentUpon>
</Compile>
@ -297,7 +299,6 @@ @@ -297,7 +299,6 @@
<Folder Include="Src\Visualizers\Graph\Utils" />
<Folder Include="Src\Visualizers\PresentationBindings" />
<Page Include="Src\Visualizers\Graph\Drawing\NodeControl.xaml" />
<Page Include="Src\Visualizers\Graph\VisualizerWPFControl.xaml" />
<Page Include="Src\Visualizers\Graph\VisualizerWPFWindow.xaml" />
</ItemGroup>
<ItemGroup>

1
src/AddIns/Misc/Debugger/Debugger.AddIn/Project/Src/Visualizers/Graph/Drawing/NodeControl.xaml

@ -18,6 +18,7 @@ @@ -18,6 +18,7 @@
<Grid.ColumnDefinitions>
<ColumnDefinition Width="Auto" />
<ColumnDefinition Width="Auto" />
<ColumnDefinition Width="Auto" />
</Grid.ColumnDefinitions>
</Grid>
</Border>

103
src/AddIns/Misc/Debugger/Debugger.AddIn/Project/Src/Visualizers/Graph/Drawing/NodeControl.xaml.cs

@ -4,6 +4,7 @@ @@ -4,6 +4,7 @@
// <owner name="Martin Koníček" email="martin.konicek@gmail.com"/>
// <version>$Revision$</version>
// </file>
using Debugger.AddIn.Visualizers.Graph.Layout;
using System;
using System.Collections.Generic;
using System.Text;
@ -21,46 +22,102 @@ using Debugger.AddIn.Visualizers.Graph; @@ -21,46 +22,102 @@ using Debugger.AddIn.Visualizers.Graph;
namespace Debugger.AddIn.Visualizers.Graph.Drawing
{
/// <summary>
/// UserControl used to display ObjectNode.
/// UserControl used to display Positione.
/// </summary>
public partial class NodeControl : UserControl
{
/// <summary>
/// Creates new NodeControl displaying PositionedNode.
/// </summary>
/// <param name="graphNode">PositionedNode displayed by the control.</param>
public NodeControl(PositionedNode graphNode) : this()
{
//this.initializeWithGraphNode(graphNode);
this.GraphNode = graphNode;
}
public NodeControl()
{
InitializeComponent();
}
private ObjectNode node;
public event EventHandler<PositionedPropertyEventArgs> Expanded;
public event EventHandler<PositionedPropertyEventArgs> Collapsed;
private PositionedNode node;
/// <summary>
/// ObjectNode that this control displays.
/// </summary>
public ObjectNode GraphNode
public PositionedNode GraphNode
{
get
{
return node;
}
set
private set
{
node = value;
int row = 0;
// dynamically create TextBlocks and insert them to the 2-column propertyGrid
foreach (var property in node.Properties)
this.node = value;
}
}
public void AddProperty(PositionedNodeProperty property)
{
propertyGrid.RowDefinitions.Add(new RowDefinition());
int nRow = propertyGrid.RowDefinitions.Count;
var row = new RowDefinition();
propertyGrid.RowDefinitions.Add(row);
if (!property.IsAtomic && !property.IsNull)
{
Button btnExpandCollapse = new Button();
btnExpandCollapse.Tag = property;
btnExpandCollapse.Content = property.IsExpanded ? "-" : "+";
btnExpandCollapse.Width = 20;
propertyGrid.Children.Add(btnExpandCollapse);
Grid.SetRow(btnExpandCollapse, nRow);
Grid.SetColumn(btnExpandCollapse, 0);
btnExpandCollapse.Click += new RoutedEventHandler(btnExpandCollapse_Click);
}
TextBlock txtName = createTextBlock(property.Name);
propertyGrid.Children.Add(txtName);
Grid.SetRow(txtName, row);
Grid.SetColumn(txtName, 0);
Grid.SetRow(txtName, nRow);
Grid.SetColumn(txtName, 1);
TextBlock txtValue = createTextBlock(property.Value);
propertyGrid.Children.Add(txtValue);
Grid.SetRow(txtValue, row);
Grid.SetColumn(txtValue, 1);
Grid.SetRow(txtValue, nRow);
Grid.SetColumn(txtValue, 2);
}
/*public void Measure()
{
this.Measure();
row++;
int nRow = 0;
// dynamically create TextBlocks and insert them to the 2-column propertyGrid
foreach (var property in node.Properties)
{
nRow++;
}
}*/
void btnExpandCollapse_Click(object sender, RoutedEventArgs e)
{
Button buttonClicked = ((Button)sender);
var property = (PositionedNodeProperty)buttonClicked.Tag;
property.IsExpanded = !property.IsExpanded;
buttonClicked.Content = property.IsExpanded ? "-" : "+";
if (property.IsExpanded)
{
OnPropertyExpanded(property);
}
else
{
OnPropertyCollapsed(property);
}
}
@ -74,5 +131,23 @@ namespace Debugger.AddIn.Visualizers.Graph.Drawing @@ -74,5 +131,23 @@ namespace Debugger.AddIn.Visualizers.Graph.Drawing
newTextblock.Padding = new Thickness(4);
return newTextblock;
}
#region event helpers
protected virtual void OnPropertyExpanded(PositionedNodeProperty property)
{
if (this.Expanded != null)
{
this.Expanded(this, new PositionedPropertyEventArgs(property));
}
}
protected virtual void OnPropertyCollapsed(PositionedNodeProperty property)
{
if (this.Collapsed != null)
{
this.Collapsed(this, new PositionedPropertyEventArgs(property));
}
}
#endregion
}
}

38
src/AddIns/Misc/Debugger/Debugger.AddIn/Project/Src/Visualizers/Graph/ExpandedNodes.cs

@ -0,0 +1,38 @@ @@ -0,0 +1,38 @@
// <file>
// <copyright see="prj:///doc/copyright.txt"/>
// <license see="prj:///doc/license.txt"/>
// <owner name="Martin Koníček" email="martin.konicek@gmail.com"/>
// <version>$Revision$</version>
// </file>
using System;
using System.Collections.Generic;
namespace Debugger.AddIn.Visualizers.Graph
{
/// <summary>
/// Remembers which expressions the user has expanded.
/// </summary>
public class ExpandedNodes
{
private Dictionary<string, bool> expandedNodes = new Dictionary<string, bool>();
public ExpandedNodes()
{
}
public bool IsExpanded(string expression)
{
return expandedNodes.ContainsKey(expression) && (expandedNodes[expression] == true);
}
public void SetExpanded(string expression)
{
expandedNodes[expression] = true;
}
public void SetCollapsed(string expression)
{
expandedNodes[expression] = false;
}
}
}

2
src/AddIns/Misc/Debugger/Debugger.AddIn/Project/Src/Visualizers/Graph/Layout/GraphMatcher.cs

@ -94,7 +94,7 @@ namespace Debugger.AddIn.Visualizers.Graph.Layout @@ -94,7 +94,7 @@ namespace Debugger.AddIn.Visualizers.Graph.Layout
private bool isSameAddress(PositionedNode node1, PositionedNode node2)
{
return node1.ObjectNode.PermanentReference.GetObjectAddress() == node2.ObjectNode.PermanentReference.GetObjectAddress();
return node1.ObjectNode.DebuggerValue.GetObjectAddress() == node2.ObjectNode.DebuggerValue.GetObjectAddress();
}
}
}

2
src/AddIns/Misc/Debugger/Debugger.AddIn/Project/Src/Visualizers/Graph/Layout/PositionedEdge.cs

@ -13,7 +13,7 @@ namespace Debugger.AddIn.Visualizers.Graph.Layout @@ -13,7 +13,7 @@ namespace Debugger.AddIn.Visualizers.Graph.Layout
/// <summary>
/// Edge with position information.
/// </summary>
public class PositionedEdge : NamedEdge<PositionedNode>
public class PositionedEdge : NamedEdge<PositionedNodeProperty, PositionedNode>
{
private IList<Point> splinePoints = new List<Point>();

7
src/AddIns/Misc/Debugger/Debugger.AddIn/Project/Src/Visualizers/Graph/Layout/PositionedGraph.cs

@ -16,7 +16,7 @@ namespace Debugger.AddIn.Visualizers.Graph.Layout @@ -16,7 +16,7 @@ namespace Debugger.AddIn.Visualizers.Graph.Layout
/// </summary>
public class PositionedGraph
{
internal List<PositionedNode> nodes = new List<PositionedNode>();
private List<PositionedNode> nodes = new List<PositionedNode>();
public System.Windows.Rect BoundingRect
{
@ -39,6 +39,11 @@ namespace Debugger.AddIn.Visualizers.Graph.Layout @@ -39,6 +39,11 @@ namespace Debugger.AddIn.Visualizers.Graph.Layout
get { return nodes; }
}
internal void AddNode(PositionedNode node)
{
this.nodes.Add(node);
}
/// <summary>
/// All edges in the graph.
/// </summary>

79
src/AddIns/Misc/Debugger/Debugger.AddIn/Project/Src/Visualizers/Graph/Layout/PositionedNode.cs

@ -12,20 +12,69 @@ using System.Windows; @@ -12,20 +12,69 @@ using System.Windows;
namespace Debugger.AddIn.Visualizers.Graph.Layout
{
/// <summary>
/// Node with added position information.
/// ObjectNode with added position information.
/// </summary>
public class PositionedNode
{
private ObjectNode objectNode;
/// <summary>
/// Underlying ObjectNode.
/// </summary>
public ObjectNode ObjectNode
{
get { return objectNode; }
}
public PositionedNode(NodeControl nodeVisualControl, ObjectNode objectNode)
public event EventHandler<PositionedPropertyEventArgs> Expanded;
public event EventHandler<PositionedPropertyEventArgs> Collapsed;
private List<PositionedNodeProperty> properties = new List<PositionedNodeProperty>();
public List<PositionedNodeProperty> Properties
{
get
{
return this.properties;
}
}
public PositionedNodeProperty AddProperty(ObjectProperty objectProperty, bool isExpanded)
{
var newProperty = new PositionedNodeProperty(objectProperty, this);
newProperty.IsExpanded = isExpanded;
this.Properties.Add(newProperty);
this.nodeVisualControl.AddProperty(newProperty);
return newProperty;
}
/// <summary>
/// Creates new PositionedNode.
/// </summary>
/// <param name="objectNode">Underlying ObjectNode.</param>
public PositionedNode(ObjectNode objectNode)
{
this.nodeVisualControl = nodeVisualControl;
this.objectNode = objectNode;
this.nodeVisualControl = new NodeControl(this); // display
this.nodeVisualControl.Expanded += new EventHandler<PositionedPropertyEventArgs>(NodeVisualControl_Expanded);
this.nodeVisualControl.Collapsed += new EventHandler<PositionedPropertyEventArgs>(NodeVisualControl_Collapsed);
}
private void NodeVisualControl_Expanded(object sender, PositionedPropertyEventArgs e)
{
// propagage event
OnPropertyExpanded(this, e);
}
private void NodeVisualControl_Collapsed(object sender, PositionedPropertyEventArgs e)
{
// propagate event
OnPropertyCollapsed(this, e);
}
public void Measure()
{
this.nodeVisualControl.Measure(new Size(500, 500));
}
public double Left { get; set; }
@ -67,8 +116,30 @@ namespace Debugger.AddIn.Visualizers.Graph.Layout @@ -67,8 +116,30 @@ namespace Debugger.AddIn.Visualizers.Graph.Layout
{
get
{
return new PositionedEdge[]{};
foreach (PositionedNodeProperty property in this.Properties)
{
if (property.Edge != null)
yield return property.Edge;
}
}
}
#region event helpers
protected virtual void OnPropertyExpanded(object sender, PositionedPropertyEventArgs propertyArgs)
{
if (this.Expanded != null)
{
this.Expanded(sender, propertyArgs);
}
}
protected virtual void OnPropertyCollapsed(object sender, PositionedPropertyEventArgs propertyArgs)
{
if (this.Collapsed != null)
{
this.Collapsed(sender, propertyArgs);
}
}
#endregion
}
}

76
src/AddIns/Misc/Debugger/Debugger.AddIn/Project/Src/Visualizers/Graph/Layout/PositionedNodeProperty.cs

@ -0,0 +1,76 @@ @@ -0,0 +1,76 @@
// <file>
// <copyright see="prj:///doc/copyright.txt"/>
// <license see="prj:///doc/license.txt"/>
// <owner name="Martin Koníček" email="martin.konicek@gmail.com"/>
// <version>$Revision$</version>
// </file>
using System;
namespace Debugger.AddIn.Visualizers.Graph.Layout
{
/// <summary>
/// <see cref="ObjectProperty"/> with outgoing <see cref="PositionedEdge"/>.
/// </summary>
public class PositionedNodeProperty
{
/// <summary>
/// Creates new PositionedNodeProperty.
/// </summary>
/// <param name="objectProperty">Underlying <see cref="ObjectProperty"/></param>
public PositionedNodeProperty(ObjectProperty objectProperty, PositionedNode containingNode)
{
this.objectProperty = objectProperty;
this.containingNode = containingNode;
}
public bool IsExpanded { get; set; }
private ObjectProperty objectProperty;
/// <summary>
/// Underlying <see cref="ObjectProperty"/>.
/// </summary>
public ObjectProperty ObjectProperty
{
get { return this.objectProperty; }
}
private PositionedNode containingNode;
/// <summary>
/// <see cref="PositionedNode"/> which contains this Property.
/// </summary>
public PositionedNode ContainingNode
{
get { return this.containingNode; }
}
/// <summary>
/// Edge outgoing from this property to another <see cref="PositionedNode"/>.
/// </summary>
public PositionedEdge Edge { get; set; }
/// <summary>
/// e.g. "Age"
/// </summary>
public string Name { get { return this.objectProperty.Name; } }
/// <summary>
/// e.g. "19"
/// </summary>
public string Value { get { return this.objectProperty.Value; } }
/// <summary>
/// Full Debugger expression used to obtain value of this property.
/// </summary>
public Debugger.Expressions.Expression Expression { get { return this.objectProperty.Expression; } }
/// <summary>
/// Is this property of atomic type? (int, string, etc.)
/// </summary>
public bool IsAtomic { get { return this.objectProperty.IsAtomic; } }
/// <summary>
/// Is the value of this property null?
/// </summary>
public bool IsNull { get { return this.objectProperty.IsNull; } }
}
}

25
src/AddIns/Misc/Debugger/Debugger.AddIn/Project/Src/Visualizers/Graph/Layout/PositionedPropertyEventArgs.cs

@ -0,0 +1,25 @@ @@ -0,0 +1,25 @@
// <file>
// <copyright see="prj:///doc/copyright.txt"/>
// <license see="prj:///doc/license.txt"/>
// <owner name="Martin Koníček" email="martin.konicek@gmail.com"/>
// <version>$Revision$</version>
// </file>
using System;
namespace Debugger.AddIn.Visualizers.Graph.Layout
{
/// <summary>
/// EventArgs carrying <see cref="PositionedNodeProperty"/>.
/// </summary>
public class PositionedPropertyEventArgs : EventArgs
{
private PositionedNodeProperty property;
public PositionedPropertyEventArgs(PositionedNodeProperty property)
{
this.property = property;
}
public PositionedNodeProperty Property { get { return this.property; } }
}
}

44
src/AddIns/Misc/Debugger/Debugger.AddIn/Project/Src/Visualizers/Graph/Layout/Tree/BoxDotFormatter.cs

@ -0,0 +1,44 @@ @@ -0,0 +1,44 @@
// <file>
// <copyright see="prj:///doc/copyright.txt"/>
// <license see="prj:///doc/license.txt"/>
// <owner name="Martin Koníček" email="martin.konicek@gmail.com"/>
// <version>$Revision$</version>
// </file>
using System;
using System.Text;
using System.Windows;
namespace Debugger.AddIn.Visualizers.Graph.Layout
{
/// <summary>
/// <see cref="DotFormatter"/> that treats node as a atomic "box". Edges go from box to box.
/// </summary>
public class BoxDotFormatter : DotFormatter
{
public BoxDotFormatter(PositionedGraph posGraph) : base(posGraph)
{
}
protected override void appendPosNode(PositionedNode node, StringBuilder builder)
{
string nodeName = genId.GetNextId().ToString();
nodeNames[node] = nodeName;
Rect neatoInput = transform.NodeToNeatoInput(node);
string dotFormatNode =
string.Format(this.neatoDoubleFormatter,
"{0} [pos=\"{1},{2}!\" width=\"{3}\" height=\"{4}\"];",
nodeName, neatoInput.Location.X, neatoInput.Location.Y, neatoInput.Width, neatoInput.Height);
builder.AppendLine(dotFormatNode);
}
protected override void appendPosEdge(PositionedEdge edge, StringBuilder builder)
{
string sourceNodeName = nodeNames[edge.Source.ContainingNode];
string targetNodeName = nodeNames[edge.Target];
builder.AppendLine(string.Format("{0} -> {1}", sourceNodeName, targetNodeName));
}
}
}

70
src/AddIns/Misc/Debugger/Debugger.AddIn/Project/Src/Visualizers/Graph/Layout/Tree/DotGraph.cs → src/AddIns/Misc/Debugger/Debugger.AddIn/Project/Src/Visualizers/Graph/Layout/Tree/DotFormatter.cs

@ -17,24 +17,24 @@ namespace Debugger.AddIn.Visualizers.Graph.Layout @@ -17,24 +17,24 @@ namespace Debugger.AddIn.Visualizers.Graph.Layout
/// <summary>
/// Converts <see cref="PositionedGraph/> to Graphviz's string (dot format) and back (from plain format).
/// </summary>
public class DotGraph
public abstract class DotFormatter
{
private PositionedGraph posGraph;
protected PositionedGraph posGraph;
NeatoPositionTransform transform;
protected NeatoPositionTransform transform;
// state (node and edge names) needed for converting back
private Dictionary<PositionedNode, string> nodeNames = new Dictionary<PositionedNode, string>();
private Dictionary<PositionedEdge, string> edgeNames = new Dictionary<PositionedEdge, string>();
protected NeatoDoubleFormatter neatoDoubleFormatter = new NeatoDoubleFormatter();
private CultureInfo formatCulture = CultureInfo.GetCultureInfo("en-US");
// state (node and edge names) needed for parsing back
protected Dictionary<PositionedNode, string> nodeNames = new Dictionary<PositionedNode, string>();
protected Dictionary<PositionedEdge, string> edgeNames = new Dictionary<PositionedEdge, string>();
/// <summary>
/// Used for generating node and edge names.
/// </summary>
private IdGenerator genId = new IdGenerator();
protected IdGenerator genId = new IdGenerator();
public DotGraph(PositionedGraph posGraph)
public DotFormatter(PositionedGraph posGraph)
{
if (posGraph.Nodes.Count() == 0)
{
@ -44,14 +44,26 @@ namespace Debugger.AddIn.Visualizers.Graph.Layout @@ -44,14 +44,26 @@ namespace Debugger.AddIn.Visualizers.Graph.Layout
this.transform = new NeatoPositionTransform(this.posGraph.BoundingRect);
}
protected abstract void appendPosNode(PositionedNode node, StringBuilder builder);
protected abstract void appendPosEdge(PositionedEdge edge, StringBuilder builder);
protected virtual string getGraphHeader()
{
return "digraph G { node [shape = box];";
}
protected virtual string getGraphFooter()
{
return "}";
}
/// <summary>
/// Gets Graphviz's dot format string for the positioned graph.
/// Gets Graphviz's dot format string for wrapped positioned graph.
/// </summary>
public string DotGraphString
public string OutputGraphInDotFormat()
{
get
{
StringBuilder dotStringBuilder = new StringBuilder("digraph G { node [shape = box];");
StringBuilder dotStringBuilder = new StringBuilder(getGraphHeader());
foreach (PositionedNode posNode in this.posGraph.Nodes)
{
@ -62,36 +74,13 @@ namespace Debugger.AddIn.Visualizers.Graph.Layout @@ -62,36 +74,13 @@ namespace Debugger.AddIn.Visualizers.Graph.Layout
appendPosEdge(posEdge, dotStringBuilder);
}
dotStringBuilder.AppendLine("}");
dotStringBuilder.AppendLine(getGraphFooter());
return dotStringBuilder.ToString();
}
}
private void appendPosNode(PositionedNode node, StringBuilder builder)
{
string nodeName = genId.GetNextId().ToString();
nodeNames[node] = nodeName;
Rect neatoInput = transform.NodeToNeatoInput(node);
string dotFormatNode =
string.Format(formatCulture,
"{0} [pos=\"{1},{2}!\" width=\"{3}\" height=\"{4}\"];",
nodeName, neatoInput.Location.X, neatoInput.Location.Y, neatoInput.Width, neatoInput.Height);
builder.AppendLine(dotFormatNode);
}
private void appendPosEdge(PositionedEdge edge, StringBuilder builder)
{
string sourceNodeName = nodeNames[edge.SourceNode];
string targetNodeName = nodeNames[edge.TargetNode];
builder.AppendLine(string.Format("{0} -> {1}", sourceNodeName, targetNodeName));
}
private bool validateSplinePoints(PositionedEdge edge)
{
// must have correct number of points: one start point and 3 points for every bezier segment
// must have correct number of points: one start point and 3 points per bezier segment
return ((edge.SplinePoints.Count - 1) % 3) == 0;
}
@ -112,6 +101,7 @@ namespace Debugger.AddIn.Visualizers.Graph.Layout @@ -112,6 +101,7 @@ namespace Debugger.AddIn.Visualizers.Graph.Layout
transform.NeatoShiftX = neatoFirstNodePos.X - firstNodePosOur.X;
transform.NeatoShiftY = neatoFirstNodePos.Y - firstNodePosOur.Y;
// assume that edges on output are in the same order as posGraph.Edges (!)
foreach (PositionedEdge posEdge in posGraph.Edges)
{
skipAfterPattern(reader, "edge ");
@ -146,7 +136,7 @@ namespace Debugger.AddIn.Visualizers.Graph.Layout @@ -146,7 +136,7 @@ namespace Debugger.AddIn.Visualizers.Graph.Layout
private double readDouble(TextReader reader)
{
return double.Parse(readWord(reader), formatCulture);
return double.Parse(readWord(reader), this.neatoDoubleFormatter.DoubleCulture);
}
private int readInt(TextReader reader)

39
src/AddIns/Misc/Debugger/Debugger.AddIn/Project/Src/Visualizers/Graph/Layout/Tree/NeatoDoubleFormatter.cs

@ -0,0 +1,39 @@ @@ -0,0 +1,39 @@
// <file>
// <copyright see="prj:///doc/copyright.txt"/>
// <license see="prj:///doc/license.txt"/>
// <owner name="Martin Koníček" email="martin.konicek@gmail.com"/>
// <version>$Revision$</version>
// </file>
using System;
using System.Globalization;
namespace Debugger.AddIn.Visualizers.Graph.Layout
{
/// <summary>
/// When used as IFormatProvider in string.Format, formats doubles to be suitable for Neato.
/// </summary>
public class NeatoDoubleFormatter : IFormatProvider, ICustomFormatter
{
private CultureInfo doubleCulture = CultureInfo.GetCultureInfo("en-US");
/// <summary>
/// CultureInfo used for formatting and parsing doubles (en-US).
/// </summary>
public CultureInfo DoubleCulture
{
get { return this.doubleCulture; }
}
public object GetFormat(Type formatType)
{
if (formatType == typeof(ICustomFormatter))
return this;
else
return null;
}
public string Format(string format, object arg, IFormatProvider formatProvider)
{
return string.Format(doubleCulture, "{0:0.000}", arg);
}
}
}

13
src/AddIns/Misc/Debugger/Debugger.AddIn/Project/Src/Visualizers/Graph/Layout/Tree/NeatoEdgeRouter.cs

@ -30,14 +30,19 @@ namespace Debugger.AddIn.Visualizers.Graph.Layout @@ -30,14 +30,19 @@ namespace Debugger.AddIn.Visualizers.Graph.Layout
/// <returns><see cref="PositionedGraph" /> with preserved node positions and calculated edge positions.</returns>
public PositionedGraph CalculateEdges(PositionedGraph graphWithNodesPositioned)
{
DotGraph dotGraph = new DotGraph(graphWithNodesPositioned);
DotFormatter dotFormatter = new RecordDotFormatter(graphWithNodesPositioned);
// start Neato.exe
NeatoProcess neatoProcess = NeatoProcess.Start();
// convert PosGraph to .dot string, pass to neato.exe
string dotGraphStringWithPositions = neatoProcess.CalculatePositions(dotGraph.DotGraphString);
// convert PosGraph to .dot string
string dotGraphString = dotFormatter.OutputGraphInDotFormat();
// pass to neato.exe
string dotGraphStringWithPositions = neatoProcess.CalculatePositions(dotGraphString);
// parse edge positions from neato's plain output format
PositionedGraph result = dotGraph.ParseEdgePositions(dotGraphStringWithPositions);
PositionedGraph result = dotFormatter.ParseEdgePositions(dotGraphStringWithPositions);
return result;
}

6
src/AddIns/Misc/Debugger/Debugger.AddIn/Project/Src/Visualizers/Graph/Layout/Tree/NeatoProcess.cs

@ -5,6 +5,7 @@ @@ -5,6 +5,7 @@
// <version>$Revision$</version>
// </file>
using System;
using System.IO;
using System.Text;
namespace Debugger.AddIn.Visualizers.Graph.Layout
@ -72,6 +73,11 @@ namespace Debugger.AddIn.Visualizers.Graph.Layout @@ -72,6 +73,11 @@ namespace Debugger.AddIn.Visualizers.Graph.Layout
/// <returns>Same graph in Graphviz plain with position information added.</returns>
public string CalculatePositions(string dotGraph)
{
/*using (var writer = new StreamWriter("logIn.gv"))
{
writer.Write(dotGraph);
}*/
neatoProcess.StandardInput.Write(dotGraph);
neatoProcess.StandardInput.Flush();
neatoProcess.StandardInput.Close();

68
src/AddIns/Misc/Debugger/Debugger.AddIn/Project/Src/Visualizers/Graph/Layout/Tree/RecordDotFormatter.cs

@ -0,0 +1,68 @@ @@ -0,0 +1,68 @@
// <file>
// <copyright see="prj:///doc/copyright.txt"/>
// <license see="prj:///doc/license.txt"/>
// <owner name="Martin Koníček" email="martin.konicek@gmail.com"/>
// <version>$Revision$</version>
// </file>
using System;
using System.Collections.Generic;
using System.Text;
using System.Windows;
namespace Debugger.AddIn.Visualizers.Graph.Layout
{
/// <summary>
/// <see cref="DotFormatter"/> that treats nodes as records of properties.
/// Edges start at property, end at node.
/// </summary>
public class RecordDotFormatter : DotFormatter
{
private Dictionary<PositionedNodeProperty, string> propertyIds = new Dictionary<PositionedNodeProperty, string>();
public RecordDotFormatter(PositionedGraph posGraph) : base(posGraph)
{
}
protected override string getGraphHeader()
{
return "digraph G { rankdir=LR; node [shape = record];";
}
protected override void appendPosNode(PositionedNode node, StringBuilder builder)
{
string nodeName = genId.GetNextId().ToString();
nodeNames[node] = nodeName;
Rect neatoInput = transform.NodeToNeatoInput(node);
StringBuilder recordLabel = new StringBuilder();
for (int i = 0; i < node.Properties.Count; i++)
{
string propertyId = "f" + genId.GetNextId().ToString();
propertyIds[node.Properties[i]] = propertyId;
recordLabel.Append(string.Format("<{0}> l", propertyId));
if (i < node.Properties.Count - 1)
{
recordLabel.Append("|");
}
}
string dotFormatNode =
string.Format(this.neatoDoubleFormatter,
"{0} [pos=\"{1},{2}!\" width=\"{3}\" height=\"{4}\" label=\"{5}\"];",
nodeName,
neatoInput.Location.X, neatoInput.Location.Y, neatoInput.Width, neatoInput.Height,
recordLabel.ToString());
builder.AppendLine(dotFormatNode);
}
protected override void appendPosEdge(PositionedEdge edge, StringBuilder builder)
{
string sourceNodeName = nodeNames[edge.Source.ContainingNode];
string sourcePropertyName = propertyIds[edge.Source];
string targetNodeName = nodeNames[edge.Target];
builder.AppendLine(string.Format("{0}:{1} -> {2}", sourceNodeName, sourcePropertyName, targetNodeName));
}
}
}

8
src/AddIns/Misc/Debugger/Debugger.AddIn/Project/Src/Visualizers/Graph/Layout/Tree/TreeEdge.cs

@ -9,9 +9,13 @@ using System; @@ -9,9 +9,13 @@ using System;
namespace Debugger.AddIn.Visualizers.Graph.Layout
{
/// <summary>
/// Description of TreeEdge.
/// Edge in the tree-layouted <see cref="PositionedGraph"/>.
/// </summary>
public class TreeEdge : PositionedEdge
public class TreeGraphEdge : PositionedEdge
{
/// <summary>
/// Is this a main edges making up the tree?
/// </summary>
public bool IsTreeEdge { get; set; }
}
}

36
src/AddIns/Misc/Debugger/Debugger.AddIn/Project/Src/Visualizers/Graph/Layout/Tree/TreeLayouter.cs

@ -36,7 +36,7 @@ namespace Debugger.AddIn.Visualizers.Graph.Layout @@ -36,7 +36,7 @@ namespace Debugger.AddIn.Visualizers.Graph.Layout
/// </summary>
/// <param name="objectGraph"></param>
/// <returns></returns>
public PositionedGraph CalculateLayout(ObjectGraph objectGraph, LayoutDirection direction)
public PositionedGraph CalculateLayout(ObjectGraph objectGraph, LayoutDirection direction, ExpandedNodes expandedNodes)
{
layoutDirection = direction;
@ -44,7 +44,7 @@ namespace Debugger.AddIn.Visualizers.Graph.Layout @@ -44,7 +44,7 @@ namespace Debugger.AddIn.Visualizers.Graph.Layout
treeNodeFor = new Dictionary<ObjectNode, TreeNode>();
seenNodes = new Dictionary<ObjectNode, object>();
TreeNode tree = buildTreeRecursive(objectGraph.Root);
TreeNode tree = buildTreeRecursive(objectGraph.Root, expandedNodes);
calculateNodePosRecursive(tree, 0, 0);
var neatoRouter = new NeatoEdgeRouter();
@ -53,39 +53,45 @@ namespace Debugger.AddIn.Visualizers.Graph.Layout @@ -53,39 +53,45 @@ namespace Debugger.AddIn.Visualizers.Graph.Layout
return resultGraph;
}
private TreeNode buildTreeRecursive(ObjectNode objectGraphNode)
private TreeNode buildTreeRecursive(ObjectNode objectGraphNode, ExpandedNodes expandedNodes)
{
seenNodes.Add(objectGraphNode, null);
NodeControl nodeVisualControl = new NodeControl();
nodeVisualControl.GraphNode = objectGraphNode;
nodeVisualControl.Measure(new Size(500, 500));
TreeNode newTreeNode = TreeNode.Create(this.layoutDirection, nodeVisualControl, objectGraphNode);
TreeNode newTreeNode = TreeNode.Create(this.layoutDirection, objectGraphNode);
newTreeNode.HorizontalMargin = horizNodeMargin;
newTreeNode.VerticalMargin = vertNodeMargin;
resultGraph.nodes.Add(newTreeNode);
resultGraph.AddNode(newTreeNode);
treeNodeFor[objectGraphNode] = newTreeNode;
double subtreeSize = 0;
foreach (ObjectProperty property in objectGraphNode.ComplexProperties)
foreach (ObjectProperty property in objectGraphNode.Properties)
{
if (property.TargetNode != null)
{
ObjectNode neighbor = property.TargetNode;
TreeNode targetTreeNode = null;
bool newEdgeIsTreeEdge = false;
if (seenNodes.ContainsKey(neighbor))
{
newTreeNode.AdditionalNeighbors.Add(new TreeEdge { Name = property.Name, SourceNode = newTreeNode, TargetNode = treeNodeFor[neighbor]});
targetTreeNode = treeNodeFor[neighbor];
newEdgeIsTreeEdge = false;
}
else
{
TreeNode newChild = buildTreeRecursive(neighbor);
newTreeNode.ChildEdges.Add(new TreeEdge { Name = property.Name, SourceNode = newTreeNode, TargetNode = newChild});
subtreeSize += newChild.SubtreeSize;
targetTreeNode = buildTreeRecursive(neighbor, expandedNodes);
newEdgeIsTreeEdge = true;
subtreeSize += targetTreeNode.SubtreeSize;
}
var posNodeProperty = newTreeNode.AddProperty(property, expandedNodes.IsExpanded(property.Expression.Code));
posNodeProperty.Edge = new TreeGraphEdge { IsTreeEdge = newEdgeIsTreeEdge, Name = property.Name, Source = posNodeProperty, Target = targetTreeNode };
}
else
{
// property.Edge stays null
newTreeNode.AddProperty(property, expandedNodes.IsExpanded(property.Expression.Code));
}
}
newTreeNode.Measure();
subtreeSize = Math.Max(newTreeNode.LateralSizeWithMargin, subtreeSize);
newTreeNode.SubtreeSize = subtreeSize;

40
src/AddIns/Misc/Debugger/Debugger.AddIn/Project/Src/Visualizers/Graph/Layout/Tree/TreeNode.cs

@ -11,18 +11,19 @@ using Debugger.AddIn.Visualizers.Graph.Drawing; @@ -11,18 +11,19 @@ using Debugger.AddIn.Visualizers.Graph.Drawing;
namespace Debugger.AddIn.Visualizers.Graph.Layout
{
/// <summary>
/// Abstract ancestor of TreeNodeLR and TreeNodeTB.
/// Node in tree-layouted <see cref="PositionedGraph"/>.
/// This is the abstract ancestor of TreeNodeLR and TreeNodeTB.
/// There are 2 dimensions - "main" and "lateral".
/// Main dimension is the dimension in which the graph depth grows (vertical when TB, horizontal when LR).
/// Lateral dimension is the other dimension. Siblings are placed next to each other in Lateral dimension.
/// </summary>
public abstract class TreeNode : PositionedNode
{
public static TreeNode Create(LayoutDirection direction, NodeControl nodeVisualControl, ObjectNode objectNode)
public static TreeNode Create(LayoutDirection direction, ObjectNode objectNode)
{
switch (direction) {
case LayoutDirection.TopBottom: return new TreeNodeTB(nodeVisualControl, objectNode);
case LayoutDirection.LeftRight: return new TreeNodeLR(nodeVisualControl, objectNode);
case LayoutDirection.TopBottom: return new TreeNodeTB(objectNode);
case LayoutDirection.LeftRight: return new TreeNodeLR(objectNode);
default: throw new DebuggerVisualizerException("Unsupported layout direction: " + direction.ToString());
}
}
@ -30,7 +31,7 @@ namespace Debugger.AddIn.Visualizers.Graph.Layout @@ -30,7 +31,7 @@ namespace Debugger.AddIn.Visualizers.Graph.Layout
public double HorizontalMargin { get; set; }
public double VerticalMargin { get; set; }
protected TreeNode(NodeControl nodeVisualControl, ObjectNode objectNode) : base(nodeVisualControl, objectNode)
protected TreeNode(ObjectNode objectNode) : base(objectNode)
{
}
@ -51,41 +52,26 @@ namespace Debugger.AddIn.Visualizers.Graph.Layout @@ -51,41 +52,26 @@ namespace Debugger.AddIn.Visualizers.Graph.Layout
public abstract double MainMargin { get; }
public abstract double LateralMargin { get; }
private List<TreeEdge> childs = new List<TreeEdge>();
public List<TreeEdge> ChildEdges
public IEnumerable<PositionedEdge> ChildEdges
{
get
{
return childs;
}
}
public IEnumerable<TreeNode> Childs
foreach (TreeGraphEdge childEdge in Edges)
{
get
if (childEdge.IsTreeEdge)
{
foreach (TreeEdge childEdge in ChildEdges)
yield return (TreeNode)childEdge.TargetNode;
yield return childEdge;
}
}
private List<TreeEdge> additionalNeighbors = new List<TreeEdge>();
public List<TreeEdge> AdditionalNeighbors
{
get
{
return additionalNeighbors;
}
}
public override IEnumerable<PositionedEdge> Edges
public IEnumerable<TreeNode> Childs
{
get
{
foreach (TreeEdge childEdge in ChildEdges)
yield return childEdge;
foreach (TreeEdge neighborEdge in AdditionalNeighbors)
yield return neighborEdge;
foreach (PositionedEdge outEdge in this.ChildEdges)
yield return (TreeNode)outEdge.Target;
}
}
}

2
src/AddIns/Misc/Debugger/Debugger.AddIn/Project/Src/Visualizers/Graph/Layout/Tree/TreeNodeLR.cs

@ -14,7 +14,7 @@ namespace Debugger.AddIn.Visualizers.Graph.Layout @@ -14,7 +14,7 @@ namespace Debugger.AddIn.Visualizers.Graph.Layout
/// </summary>
public class TreeNodeLR: TreeNode
{
public TreeNodeLR(NodeControl nodeControl, ObjectNode objectNode) : base(nodeControl, objectNode)
public TreeNodeLR(ObjectNode objectNode) : base(objectNode)
{
}

2
src/AddIns/Misc/Debugger/Debugger.AddIn/Project/Src/Visualizers/Graph/Layout/Tree/TreeNodeTB.cs

@ -14,7 +14,7 @@ namespace Debugger.AddIn.Visualizers.Graph.Layout @@ -14,7 +14,7 @@ namespace Debugger.AddIn.Visualizers.Graph.Layout
/// </summary>
public class TreeNodeTB : TreeNode
{
public TreeNodeTB(NodeControl nodeControl, ObjectNode objectNode) : base(nodeControl, objectNode)
public TreeNodeTB(ObjectNode objectNode) : base(objectNode)
{
}

4
src/AddIns/Misc/Debugger/Debugger.AddIn/Project/Src/Visualizers/Graph/ObjectGraph/NamedEdge.cs

@ -28,11 +28,11 @@ namespace Debugger.AddIn.Visualizers.Graph @@ -28,11 +28,11 @@ namespace Debugger.AddIn.Visualizers.Graph
/// <summary>
/// Target node of the edge.
/// </summary>
public TTarget TargetNode { get; set; }
public TTarget Target { get; set; }
/// <summary>
/// Source node of the edge.
/// </summary>
public TSource SourceNode { get; set; }
public TSource Source { get; set; }
}
}

3
src/AddIns/Misc/Debugger/Debugger.AddIn/Project/Src/Visualizers/Graph/ObjectGraph/ObjectGraph.cs

@ -38,10 +38,11 @@ namespace Debugger.AddIn.Visualizers.Graph @@ -38,10 +38,11 @@ namespace Debugger.AddIn.Visualizers.Graph
get { return _nodes; }
}
/*
/// <summary>
/// All edges in the graph.
/// </summary>
/*public IEnumerable<ObjectEdge> Edges
public IEnumerable<ObjectEdge> Edges
{
get
{

109
src/AddIns/Misc/Debugger/Debugger.AddIn/Project/Src/Visualizers/Graph/ObjectGraph/ObjectGraphBuilder.cs

@ -43,10 +43,13 @@ namespace Debugger.AddIn.Visualizers.Graph @@ -43,10 +43,13 @@ namespace Debugger.AddIn.Visualizers.Graph
/// The underlying debugger service used for getting expression values.
/// </summary>
private WindowsDebugger debuggerService;
private ObjectGraph resultGraph;
/// <summary>
/// The resulting object graph.
/// Underlying object graph data struture.
/// </summary>
private ObjectGraph resultGraph;
public ObjectGraph ResultGraph { get { return this.resultGraph; } }
/// <summary>
/// System.Runtime.CompilerServices.GetHashCode method, for obtaining non-overriden hash codes from debuggee.
/// </summary>
@ -80,7 +83,7 @@ namespace Debugger.AddIn.Visualizers.Graph @@ -80,7 +83,7 @@ namespace Debugger.AddIn.Visualizers.Graph
/// </summary>
/// <param name="expression">Expression valid in the program being debugged (eg. variable name)</param>
/// <returns>Object graph</returns>
public ObjectGraph BuildGraphForExpression(string expression)
public ObjectGraph BuildGraphForExpression(string expression, ExpandedNodes expandedNodes)
{
if (string.IsNullOrEmpty(expression))
{
@ -92,37 +95,52 @@ namespace Debugger.AddIn.Visualizers.Graph @@ -92,37 +95,52 @@ namespace Debugger.AddIn.Visualizers.Graph
// empty graph for null expression
if (!debuggerService.GetValueFromName(expression).IsNull)
{
resultGraph.Root = buildGraphRecursive(debuggerService.GetValueFromName(expression).GetPermanentReference());
//resultGraph.Root = buildGraphRecursive(debuggerService.GetValueFromName(expression).GetPermanentReference(), expandedNodes);
resultGraph.Root = createNewNode(debuggerService.GetValueFromName(expression).GetPermanentReference());
loadNodeProperties(resultGraph.Root);
loadChildrenRecursive(resultGraph.Root, expandedNodes);
}
return resultGraph;
}
public ObjectNode ObtainNodeForExpression(Expression expr, out bool createdNewNode)
{
return ObtainNodeForValue(getPermanentReference(expr), out createdNewNode);
}
public ObjectNode ObtainNodeForExpression(Expression expr)
{
bool createdNewNode; // ignore (caller is not interested, otherwise he would use the other overload)
return ObtainNodeForExpression(expr, out createdNewNode);
}
/// <summary>
/// Builds the subgraph representing given value.
/// Returns node in the graph that represents given value, or returns new node if no node found.
/// </summary>
/// <param name="rootValue">The Value for which the subgraph will be built.</param>
/// <returns>ObjectNode representing the value + all recursive members.</returns>
private ObjectNode buildGraphRecursive(Value rootValue)
/// <param name="value">Value for which to obtain the node/</param>
/// <param name="createdNew">True if new node was created, false if existing node was returned.</param>
public ObjectNode ObtainNodeForValue(Value value, out bool createdNew)
{
ObjectNode thisNode = createNewNode(rootValue);
// David: by calling this, we get an array of values, most of them probably invalid,
// it would be nice to be able to get a collection of 'values'
// that are valid (basically a snapshot of object's state)
// - a collection of custom objects,
// that contain the string value and DebugType,
// and can enumerate child values.
// It would be also nice to return IEnumerable or ReadonlyCollection
// http://blogs.msdn.com/ericlippert/archive/2008/09/22/arrays-considered-somewhat-harmful.aspx
/*string[] memberValues = rootValue.GetMemberValuesAsString(_bindingFlags);
foreach (string memberValue in memberValues)
createdNew = false;
ObjectNode nodeForValue = getExistingNodeForValue(value);
if (nodeForValue == null)
{
//Value memberValuePerm = memberValue.GetPermanentReference();
}*/
// if no node for memberValue exists, create it
nodeForValue = createNewNode(value);
loadNodeProperties(nodeForValue);
createdNew = true;
}
return nodeForValue;
}
foreach(Expression memberExpr in rootValue.Expression.AppendObjectMembers(rootValue.Type, _bindingFlags))
/// <summary>
/// Fills node contents by adding properties.
/// </summary>
/// <param name="thisNode"></param>
private void loadNodeProperties(ObjectNode thisNode)
{
foreach(Expression memberExpr in thisNode.DebuggerValue.Expression.AppendObjectMembers(thisNode.DebuggerValue.Type, _bindingFlags))
{
checkIsOfSupportedType(memberExpr);
@ -135,29 +153,44 @@ namespace Debugger.AddIn.Visualizers.Graph @@ -135,29 +153,44 @@ namespace Debugger.AddIn.Visualizers.Graph
}
else
{
// for object members, complex properties are added
ObjectNode targetNode = null;
if (!isNull(memberExpr))
bool memberIsNull = isNull(memberExpr);
thisNode.AddComplexProperty(memberName, "", memberExpr, targetNode, memberIsNull);
}
}
}
/// <summary>
/// Creates child nodes of this node for each complex property and connects them to property.TargetNode.
/// </summary>
/// <param name="thisNode"></param>
/// <param name="expandedNodes"></param>
private void loadChildrenRecursive(ObjectNode thisNode, ExpandedNodes expandedNodes)
{
foreach(ObjectProperty complexProperty in thisNode.ComplexProperties)
{
Expression memberExpr = complexProperty.Expression;
ObjectNode targetNode = null;
if (!complexProperty.IsNull && expandedNodes.IsExpanded(memberExpr.Code))
{
// for object members, edges are added
Value memberValue = getPermanentReference(memberExpr);
// if node for memberValue already exists, only add edge to it (so loops etc. are solved correctly)
targetNode = getNodeForValue(memberValue);
if (targetNode == null)
bool createdNew;
// get existing node (loop) or create new
targetNode = ObtainNodeForValue(memberValue, out createdNew);
if (createdNew)
{
// if no node for memberValue exists, build the subgraph for the value
targetNode = buildGraphRecursive(memberValue);
// if member node is new, recursively build its subtree
loadChildrenRecursive(targetNode, expandedNodes);
}
}
else
{
targetNode = null;
}
thisNode.AddComplexProperty(memberName, "", memberExpr, targetNode);
}
complexProperty.TargetNode = targetNode;
}
return thisNode;
}
/// <summary>
@ -176,7 +209,7 @@ namespace Debugger.AddIn.Visualizers.Graph @@ -176,7 +209,7 @@ namespace Debugger.AddIn.Visualizers.Graph
// permanent reference to the object this node represents is useful for graph building,
// and matching nodes in animations
newNode.PermanentReference = permanentReference;
newNode.DebuggerValue = permanentReference;
return newNode;
}
@ -186,7 +219,7 @@ namespace Debugger.AddIn.Visualizers.Graph @@ -186,7 +219,7 @@ namespace Debugger.AddIn.Visualizers.Graph
/// </summary>
/// <param name="value">Valid value representing an instance.</param>
/// <returns></returns>
private ObjectNode getNodeForValue(Value value)
private ObjectNode getExistingNodeForValue(Value value)
{
int objectHashCode = invokeGetHashCode(value);
// are there any nodes with the same hash code?
@ -201,7 +234,7 @@ namespace Debugger.AddIn.Visualizers.Graph @@ -201,7 +234,7 @@ namespace Debugger.AddIn.Visualizers.Graph
// (hash codes are not uniqe - http://stackoverflow.com/questions/750947/-net-unique-object-identifier)
ulong objectAddress = value.GetObjectAddress();
ObjectNode nodeWithSameAddress = nodesWithSameHashCode.Find(
node => { return objectAddress == node.PermanentReference.GetObjectAddress(); } );
node => { return node.DebuggerValue.GetObjectAddress() == objectAddress; } );
return nodeWithSameAddress;
}
}

34
src/AddIns/Misc/Debugger/Debugger.AddIn/Project/Src/Visualizers/Graph/ObjectGraph/ObjectNode.cs

@ -17,10 +17,17 @@ namespace Debugger.AddIn.Visualizers.Graph @@ -17,10 +17,17 @@ namespace Debugger.AddIn.Visualizers.Graph
public class ObjectNode
{
/// <summary>
/// Additional info useful for internal algorithms, not to be visible to the user.
/// Permanent reference to the value in the the debugee this node represents.
/// </summary>
internal Debugger.Value DebuggerValue { get; set; }
/// <summary>
/// Hash code in the debuggee of the DebuggerValue this node represents.
/// </summary>
internal Debugger.Value PermanentReference { get; set; }
internal int HashCode { get; set; }
/// <summary>
/// Expression used to obtain this node.
/// </summary>
public Expressions.Expression Expression { get { return this.DebuggerValue.Expression; } }
/*private List<ObjectEdge> _edges = new List<ObjectEdge>();
/// <summary>
@ -42,16 +49,25 @@ namespace Debugger.AddIn.Visualizers.Graph @@ -42,16 +49,25 @@ namespace Debugger.AddIn.Visualizers.Graph
class PropertyComparer : IComparer<ObjectProperty>
{
public int Compare(ObjectProperty prop1, ObjectProperty prop2)
{
// order by IsAtomic, Name
int atomic = prop2.IsAtomic.CompareTo(prop1.IsAtomic);
if (atomic != 0)
{
return atomic;
}
else
{
return prop1.Name.CompareTo(prop2.Name);
}
}
}
private static PropertyComparer propertySortComparer = new PropertyComparer();
private bool sorted = false;
private List<ObjectProperty> _properties = new List<ObjectProperty>();
private List<ObjectProperty> properties = new List<ObjectProperty>();
/// <summary>
/// Properties (either atomic or complex) of the object this node represents.
/// </summary>
@ -61,10 +77,10 @@ namespace Debugger.AddIn.Visualizers.Graph @@ -61,10 +77,10 @@ namespace Debugger.AddIn.Visualizers.Graph
{
if (!sorted)
{
_properties.Sort(propertySortComparer);
properties.Sort(propertySortComparer);
sorted = true;
}
return _properties;
return properties;
}
}
/// <summary>
@ -87,17 +103,17 @@ namespace Debugger.AddIn.Visualizers.Graph @@ -87,17 +103,17 @@ namespace Debugger.AddIn.Visualizers.Graph
/// </summary>
internal void AddAtomicProperty(string name, string value, Expression expression)
{
_properties.Add(new ObjectProperty
properties.Add(new ObjectProperty
{ Name = name, Value = value, Expression = expression, IsAtomic = true, TargetNode = null });
}
/// <summary>
/// Adds complex property.
/// </summary>
internal void AddComplexProperty(string name, string value, Expression expression, ObjectNode targetNode)
internal void AddComplexProperty(string name, string value, Expression expression, ObjectNode targetNode, bool isNull)
{
_properties.Add(new ObjectProperty
{ Name = name, Value = value, Expression = expression, IsAtomic = false, TargetNode = targetNode });
properties.Add(new ObjectProperty
{ Name = name, Value = value, Expression = expression, IsAtomic = false, TargetNode = targetNode, IsNull = isNull });
}
}
}

13
src/AddIns/Misc/Debugger/Debugger.AddIn/Project/Src/Visualizers/Graph/ObjectGraph/ObjectProperty.cs

@ -19,21 +19,30 @@ namespace Debugger.AddIn.Visualizers.Graph @@ -19,21 +19,30 @@ namespace Debugger.AddIn.Visualizers.Graph
/// e.g. "Age"
/// </summary>
public string Name { get; set; }
/// <summary>
/// e.g. "19"
/// </summary>
public string Value { get; set; }
/// <summary>
/// Expression used for obtaining this property
/// </summary>
public Debugger.Expressions.Expression Expression { get; set; }
/// <summary>
/// Is this property of atomic type? (int, string, etc.)
/// </summary>
public bool IsAtomic { get; set; }
/// <summary>
/// Node that this property points to. Can be null. Always null if <see cref="IsAtomic"/> is true.
/// </summary>
public ObjectNode TargetNode { get; set; }
/// <summary>
/// Is this property of atomic type? (int, string, etc.)
/// Is this property value null? Only meaningful if <see cref="IsAtomic"/> is false.
/// </summary>
public bool IsAtomic { get; set; }
public bool IsNull { get; set; }
}
}

39
src/AddIns/Misc/Debugger/Debugger.AddIn/Project/Src/Visualizers/Graph/ObjectGraphVisualizerViewContent.cs

@ -1,39 +0,0 @@ @@ -1,39 +0,0 @@
// <file>
// <copyright see="prj:///doc/copyright.txt"/>
// <license see="prj:///doc/license.txt"/>
// <owner name="Martin Koníèek" email="martin.konicek@gmail.com"/>
// <version>$Revision$</version>
// </file>
using System;
using System.Text;
using System.Windows.Forms;
using ICSharpCode.Core;
using ICSharpCode.SharpDevelop;
using ICSharpCode.SharpDevelop.Gui;
namespace Debugger.AddIn.Visualizers.Graph
{
/// <summary>
/// ViewContent of the visualizer.
/// </summary>
public class ObjectGraphVisualizerViewContent : AbstractViewContent
{
VisualizerWinFormsControl control = new VisualizerWinFormsControl();
/// <summary>
/// The <see cref="System.Windows.Forms.Control"/> representing the view.
/// </summary>
public override object Control
{
get
{
return control;
}
}
public ObjectGraphVisualizerViewContent()
{
this.TitleName = "Object graph visualizer";
}
}
}

12
src/AddIns/Misc/Debugger/Debugger.AddIn/Project/Src/Visualizers/Graph/VisualizerWPFControl.xaml

@ -1,12 +0,0 @@ @@ -1,12 +0,0 @@
<UserControl x:Class="Debugger.AddIn.Visualizers.Graph.VisualizerWPFControl"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" Height="300" Width="300">
<StackPanel>
<StackPanel Orientation="Horizontal">
<TextBlock VerticalAlignment="Center" Padding="4">Expression:</TextBlock>
<TextBox VerticalAlignment="Center" Margin="4" Width="100"></TextBox>
<Button Padding="4" Margin="4">Inspect</Button>
</StackPanel>
<Canvas></Canvas>
</StackPanel>
</UserControl>

33
src/AddIns/Misc/Debugger/Debugger.AddIn/Project/Src/Visualizers/Graph/VisualizerWPFControl.xaml.cs

@ -1,33 +0,0 @@ @@ -1,33 +0,0 @@
// <file>
// <copyright see="prj:///doc/copyright.txt"/>
// <license see="prj:///doc/license.txt"/>
// <owner name="Martin Koníček" email="martin.konicek@gmail.com"/>
// <version>$Revision$</version>
// </file>
using System;
using System.Collections.Generic;
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.Media.Imaging;
using System.Windows.Navigation;
using System.Windows.Shapes;
namespace Debugger.AddIn.Visualizers.Graph
{
/// <summary>
/// Interaction logic for VisualizerWPFControl.xaml
/// </summary>
public partial class VisualizerWPFControl : UserControl
{
public VisualizerWPFControl()
{
InitializeComponent();
}
}
}

71
src/AddIns/Misc/Debugger/Debugger.AddIn/Project/Src/Visualizers/Graph/VisualizerWPFWindow.xaml.cs

@ -31,11 +31,17 @@ namespace Debugger.AddIn.Visualizers.Graph @@ -31,11 +31,17 @@ namespace Debugger.AddIn.Visualizers.Graph
private WindowsDebugger debuggerService;
private EnumViewModel<LayoutDirection> layoutViewModel;
private ObjectGraph objectGraph;
private ObjectGraphBuilder objectGraphBuilder;
private PositionedGraph oldGraph;
private PositionedGraph currentGraph;
private PositionedGraph oldPosGraph;
private PositionedGraph currentPosGraph;
private GraphDrawer graphDrawer;
/// <summary>
/// Long-lived map telling which nodes the user expanded.
/// </summary>
private ExpandedNodes expandedNodes;
public VisualizerWPFWindow()
{
InitializeComponent();
@ -52,6 +58,8 @@ namespace Debugger.AddIn.Visualizers.Graph @@ -52,6 +58,8 @@ namespace Debugger.AddIn.Visualizers.Graph
this.DataContext = this.layoutViewModel;
this.graphDrawer = new GraphDrawer(this.canvas);
this.expandedNodes = new ExpandedNodes();
}
public void debuggerService_IsProcessRunningChanged(object sender, EventArgs e)
@ -84,29 +92,30 @@ namespace Debugger.AddIn.Visualizers.Graph @@ -84,29 +92,30 @@ namespace Debugger.AddIn.Visualizers.Graph
void refreshGraph()
{
ObjectGraphBuilder graphBuilder = new ObjectGraphBuilder(debuggerService);
this.objectGraph = null;
this.objectGraph = rebuildGraph();
layoutGraph(this.objectGraph);
//GraphDrawer drawer = new GraphDrawer(graph);
//drawer.Draw(canvas);
}
ObjectGraph rebuildGraph()
{
this.objectGraphBuilder = new ObjectGraphBuilder(debuggerService);
try
{
ICSharpCode.Core.LoggingService.Debug("Debugger visualizer: Building graph for expression: " + txtExpression.Text);
this.objectGraph = graphBuilder.BuildGraphForExpression(txtExpression.Text);
return this.objectGraphBuilder.BuildGraphForExpression(txtExpression.Text, this.expandedNodes);
}
catch(DebuggerVisualizerException ex)
{
guiHandleException(ex);
return;
return null;
}
catch(Debugger.GetValueException ex)
{
guiHandleException(ex);
return;
return null;
}
layoutGraph(this.objectGraph);
//GraphDrawer drawer = new GraphDrawer(graph);
//drawer.Draw(canvas);
}
void layoutGraph(ObjectGraph graph)
@ -114,11 +123,12 @@ namespace Debugger.AddIn.Visualizers.Graph @@ -114,11 +123,12 @@ namespace Debugger.AddIn.Visualizers.Graph
ICSharpCode.Core.LoggingService.Debug("Debugger visualizer: Calculating graph layout");
Layout.TreeLayouter layouter = new Layout.TreeLayouter();
this.oldGraph = this.currentGraph;
this.currentGraph = layouter.CalculateLayout(graph, layoutViewModel.SelectedEnumValue);
this.oldPosGraph = this.currentPosGraph;
this.currentPosGraph = layouter.CalculateLayout(graph, layoutViewModel.SelectedEnumValue, this.expandedNodes);
registerExpandCollapseEvents(this.currentPosGraph);
var graphDiff = new GraphMatcher().MatchGraphs(oldGraph, currentGraph);
this.graphDrawer.StartAnimation(oldGraph, currentGraph, graphDiff);
var graphDiff = new GraphMatcher().MatchGraphs(oldPosGraph, currentPosGraph);
this.graphDrawer.StartAnimation(oldPosGraph, currentPosGraph, graphDiff);
//this.graphDrawer.Draw(currentGraph);
}
@ -126,5 +136,34 @@ namespace Debugger.AddIn.Visualizers.Graph @@ -126,5 +136,34 @@ namespace Debugger.AddIn.Visualizers.Graph
{
MessageBox.Show(ex.Message, "Exception", MessageBoxButton.OK, MessageBoxImage.Error);
}
void registerExpandCollapseEvents(PositionedGraph posGraph)
{
foreach (var node in posGraph.Nodes)
{
node.Expanded += new EventHandler<PositionedPropertyEventArgs>(node_Expanded);
node.Collapsed += new EventHandler<PositionedPropertyEventArgs>(node_Collapsed);
}
}
void node_Expanded(object sender, PositionedPropertyEventArgs e)
{
// remember this property is expanded (for later graph rebuilds)
expandedNodes.SetExpanded(e.Property.Expression.Code);
// add edge (+ possibly node) to underlying object graph (no need to rebuild)
e.Property.ObjectProperty.TargetNode = this.objectGraphBuilder.ObtainNodeForExpression(e.Property.Expression);
layoutGraph(this.objectGraph);
}
void node_Collapsed(object sender, PositionedPropertyEventArgs e)
{
// remember this property is collapsed (for later graph rebuilds)
expandedNodes.SetCollapsed(e.Property.Expression.Code);
// just remove edge from underlying object graph (no need to rebuild)
e.Property.ObjectProperty.TargetNode = null;
layoutGraph(this.objectGraph);
}
}
}

92
src/AddIns/Misc/Debugger/Debugger.AddIn/Project/Src/Visualizers/Graph/VisualizerWinFormsControl.Designer.cs generated

@ -1,92 +0,0 @@ @@ -1,92 +0,0 @@
namespace Debugger.AddIn.Visualizers.Graph
{
partial class VisualizerWinFormsControl
{
/// <summary>
/// Designer variable used to keep track of non-visual components.
/// </summary>
private System.ComponentModel.IContainer components = null;
/// <summary>
/// Disposes resources used by the control.
/// </summary>
/// <param name="disposing">true if managed resources should be disposed; otherwise, false.</param>
protected override void Dispose(bool disposing)
{
if (disposing) {
if (components != null) {
components.Dispose();
}
}
base.Dispose(disposing);
}
/// <summary>
/// This method is required for Windows Forms designer support.
/// Do not change the method contents inside the source code editor. The Forms designer might
/// not be able to load this method if it was changed manually.
/// </summary>
private void InitializeComponent()
{
this.components = new System.ComponentModel.Container();
this.txtExpression = new System.Windows.Forms.TextBox();
this.btnInspect = new System.Windows.Forms.Button();
this.lblInfo = new System.Windows.Forms.Label();
this.lblExpression = new System.Windows.Forms.Label();
this.toolTip1 = new System.Windows.Forms.ToolTip(this.components);
this.SuspendLayout();
//
// txtExpression
//
this.txtExpression.Location = new System.Drawing.Point(88, 13);
this.txtExpression.Name = "txtExpression";
this.txtExpression.Size = new System.Drawing.Size(131, 20);
this.txtExpression.TabIndex = 0;
this.toolTip1.SetToolTip(this.txtExpression, "Expression (e.g. variable name) to be inspected");
//
// btnInspect
//
this.btnInspect.Location = new System.Drawing.Point(225, 10);
this.btnInspect.Name = "btnInspect";
this.btnInspect.Size = new System.Drawing.Size(75, 23);
this.btnInspect.TabIndex = 1;
this.btnInspect.Text = "Inspect";
this.btnInspect.UseVisualStyleBackColor = true;
this.btnInspect.Click += new System.EventHandler(this.BtnInspectClick);
//
// lblInfo
//
this.lblInfo.Location = new System.Drawing.Point(11, 58);
this.lblInfo.Name = "lblInfo";
this.lblInfo.Size = new System.Drawing.Size(349, 23);
this.lblInfo.TabIndex = 2;
this.lblInfo.Text = "< Result >";
//
// lblExpression
//
this.lblExpression.Location = new System.Drawing.Point(11, 14);
this.lblExpression.Name = "lblExpression";
this.lblExpression.Size = new System.Drawing.Size(71, 23);
this.lblExpression.TabIndex = 4;
this.lblExpression.Text = "Expression:";
//
// VisualizerWinFormsControl
//
this.AutoScaleDimensions = new System.Drawing.SizeF(6F, 13F);
this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font;
this.Controls.Add(this.lblExpression);
this.Controls.Add(this.lblInfo);
this.Controls.Add(this.btnInspect);
this.Controls.Add(this.txtExpression);
this.Name = "VisualizerWinFormsControl";
this.Size = new System.Drawing.Size(525, 426);
this.ResumeLayout(false);
this.PerformLayout();
}
private System.Windows.Forms.Button btnInspect;
private System.Windows.Forms.ToolTip toolTip1;
private System.Windows.Forms.Label lblExpression;
private System.Windows.Forms.Label lblInfo;
private System.Windows.Forms.TextBox txtExpression;
}
}

84
src/AddIns/Misc/Debugger/Debugger.AddIn/Project/Src/Visualizers/Graph/VisualizerWinFormsControl.cs

@ -1,84 +0,0 @@ @@ -1,84 +0,0 @@
// <file>
// <copyright see="prj:///doc/copyright.txt"/>
// <license see="prj:///doc/license.txt"/>
// <owner name="Martin Koníèek" email="martin.konicek@gmail.com"/>
// <version>$Revision$</version>
// </file>
using System;
using System.ComponentModel;
using System.Drawing;
using System.Windows.Forms;
using System.Linq;
using ICSharpCode.SharpDevelop.Debugging;
using ICSharpCode.SharpDevelop.Services;
namespace Debugger.AddIn.Visualizers.Graph
{
/// <summary>
/// Windows forms control making up the object graph visualizer user interface/
/// </summary>
public partial class VisualizerWinFormsControl : UserControl
{
WindowsDebugger _debuggerService = null;
public VisualizerWinFormsControl()
{
//
// The InitializeComponent() call is required for Windows Forms designer support.
//
InitializeComponent();
_debuggerService = DebuggerService.CurrentDebugger as WindowsDebugger;
if (_debuggerService == null)
throw new ApplicationException("Only windows debugger is currently supported");
_debuggerService.IsProcessRunningChanged += new EventHandler(debuggerService_IsProcessRunningChanged);
}
public void debuggerService_IsProcessRunningChanged(object sender, EventArgs e)
{
// on step, breakpoint hit
if (!_debuggerService.IsProcessRunning)
{
refreshGraph();
}
}
void BtnInspectClick(object sender, EventArgs e)
{
refreshGraph();
}
void refreshGraph()
{
ObjectGraphBuilder graphBuilder = new ObjectGraphBuilder(_debuggerService);
ObjectGraph graph = null;
try
{
graph = graphBuilder.BuildGraphForExpression(txtExpression.Text);
}
catch(DebuggerVisualizerException ex)
{
guiHandleException(ex);
return;
}
catch(Debugger.GetValueException ex)
{
guiHandleException(ex);
return;
}
// just a simple message for checking the graph is build ok, will be replaced by graph drawing of course
//lblInfo.Text = string.Format("Done. Number of graph nodes: {0}, number of edges: {1}", graph.Nodes.Count(), graph.Edges.Count());
}
void guiHandleException(System.Exception ex)
{
lblInfo.Text = "< Result >";
MessageBox.Show(ex.Message, "Exception", MessageBoxButtons.OK, MessageBoxIcon.Information);
}
}
}

4
src/AddIns/Misc/Debugger/Debugger.Tests/Project/Src/TestPrograms/MemoryReadWrite.cs

@ -75,8 +75,8 @@ namespace Debugger.Tests { @@ -75,8 +75,8 @@ namespace Debugger.Tests {
<ModuleLoaded>MemoryReadWrite.exe (Has symbols)</ModuleLoaded>
<ModuleLoaded>System.dll (No symbols)</ModuleLoaded>
<DebuggingPaused>Break MemoryReadWrite.cs:18,4-18,40</DebuggingPaused>
<hello>0 A 33 79 6 0 0 0 5 0 0 0 48 0 65 0 6C 0 6C 0 6F 0 </hello>
<world>0 A 33 79 7 0 0 0 6 0 0 0 20 0 20 0 20 0 20 0 20 0 21 0 </world>
<hello>0 A 4D 3 6 0 0 0 5 0 0 0 48 0 65 0 6C 0 6C 0 6F 0 </hello>
<world>0 A 4D 3 7 0 0 0 6 0 0 0 20 0 20 0 20 0 20 0 20 0 21 0 </world>
<ModuleLoaded>System.Configuration.dll (No symbols)</ModuleLoaded>
<ModuleLoaded>System.Xml.dll (No symbols)</ModuleLoaded>
<LogMessage>Hello world!\r\n</LogMessage>

6
src/AddIns/Misc/UnitTesting/Test/Utils/MockProjectContent.cs

@ -180,5 +180,11 @@ namespace UnitTesting.Tests.Utils @@ -180,5 +180,11 @@ namespace UnitTesting.Tests.Utils
{
throw new NotImplementedException();
}
public string AssemblyName {
get {
throw new NotImplementedException();
}
}
}
}

1
src/Libraries/AvalonDock/AvalonDock.csproj

@ -76,6 +76,7 @@ @@ -76,6 +76,7 @@
<Compile Include="AlignedImage.cs" />
<Compile Include="AvalonDockBrushes.cs" />
<Compile Include="ContextMenuElement.cs" />
<Compile Include="DeserializationCallbackEventArgs.cs" />
<Compile Include="DockableContent.cs" />
<Compile Include="DockableFloatingWindow.cs" />
<Compile Include="DockablePane.cs" />

25
src/Libraries/AvalonDock/DeserializationCallbackEventArgs.cs

@ -0,0 +1,25 @@ @@ -0,0 +1,25 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
namespace AvalonDock
{
public class DeserializationCallbackEventArgs : EventArgs
{
public DeserializationCallbackEventArgs(string contentName)
{
Name = contentName;
}
/// <summary>
/// Gets the name of the content to deserialize
/// </summary>
public string Name { get; protected set; }
/// <summary>
/// Gets/Sets the content manually deserialized
/// </summary>
public DockableContent Content { get; set; }
}
}

8
src/Libraries/AvalonDock/DockableContent.cs

@ -156,6 +156,8 @@ namespace AvalonDock @@ -156,6 +156,8 @@ namespace AvalonDock
public readonly double Width;
public readonly double Height;
public readonly AnchorStyle Anchor = AnchorStyle.None;
public DockableContentStateAndPosition(
DockableContent cntToSave)
{
@ -163,6 +165,12 @@ namespace AvalonDock @@ -163,6 +165,12 @@ namespace AvalonDock
ChildIndex = ContainerPane.Items.IndexOf(cntToSave);
Width = ContainerPane.ActualWidth;
Height = ContainerPane.ActualHeight;
DockablePane dockablePane = ContainerPane as DockablePane;
if (dockablePane != null)
{
Anchor = dockablePane.Anchor;
}
}
}

6
src/Libraries/AvalonDock/DockablePane.cs

@ -47,6 +47,10 @@ namespace AvalonDock @@ -47,6 +47,10 @@ namespace AvalonDock
/// </summary>
public enum AnchorStyle
{
/// <summary>
/// No anchor style, while content is hosted in a <see cref="DocumentPane"/> or a <see cref="FloatingWindow"/>
/// </summary>
None,
/// <summary>
/// Top border anchor
/// </summary>
@ -135,7 +139,7 @@ namespace AvalonDock @@ -135,7 +139,7 @@ namespace AvalonDock
// Using a DependencyProperty as the backing store for Anchor. This enables animation, styling, binding, etc...
public static readonly DependencyPropertyKey AnchorPropertyKey =
DependencyProperty.RegisterAttachedReadOnly("Anchor", typeof(AnchorStyle), typeof(DockablePane), new UIPropertyMetadata(AnchorStyle.Left));
DependencyProperty.RegisterAttachedReadOnly("Anchor", typeof(AnchorStyle), typeof(DockablePane), new UIPropertyMetadata(AnchorStyle.None));
public override void OnApplyTemplate()

130
src/Libraries/AvalonDock/DockingManager.cs

@ -213,8 +213,8 @@ namespace AvalonDock @@ -213,8 +213,8 @@ namespace AvalonDock
}
set
{
if (_activeDocument != value &&
value.ContainerPane is DocumentPane)
if (_activeDocument != value/* &&
value.ContainerPane is DocumentPane*/)
{
List<ManagedContent> listOfAllDocuments = FindContents<ManagedContent>();
listOfAllDocuments.ForEach((ManagedContent cnt) =>
@ -685,6 +685,9 @@ namespace AvalonDock @@ -685,6 +685,9 @@ namespace AvalonDock
//remove the pane from its original children collection
FrameworkElement parentElement = paneToAnchor.Parent as FrameworkElement;
if (anchor == AnchorStyle.None)
anchor = AnchorStyle.Right;
//Change anchor border according to FlowDirection
if (FlowDirection == FlowDirection.RightToLeft)
{
@ -801,6 +804,9 @@ namespace AvalonDock @@ -801,6 +804,9 @@ namespace AvalonDock
/// <param name="anchor"></param>
public void Anchor(Pane paneToAnchor, Pane relativePane, AnchorStyle anchor)
{
if (anchor == AnchorStyle.None)
anchor = AnchorStyle.Right;
//Change anchor border according to FlowDirection
if (FlowDirection == FlowDirection.RightToLeft)
{
@ -832,6 +838,9 @@ namespace AvalonDock @@ -832,6 +838,9 @@ namespace AvalonDock
/// <param name="anchor"></param>
public void Anchor(DockablePane paneToAnchor, DocumentPane relativePane, AnchorStyle anchor)
{
if (anchor == AnchorStyle.None)
anchor = AnchorStyle.Right;
//get a reference to the resizingpanel container of relativePane
ResizingPanel relativePaneContainer = LogicalTreeHelper.GetParent(relativePane) as ResizingPanel;
DocumentPaneResizingPanel relativeDocumentPaneContainer = relativePane.GetParentDocumentPaneResizingPanel();
@ -981,6 +990,9 @@ namespace AvalonDock @@ -981,6 +990,9 @@ namespace AvalonDock
/// <param name="anchor"></param>
public void Anchor(DocumentPane paneToAnchor, DocumentPane relativePane, AnchorStyle anchor)
{
if (anchor == AnchorStyle.None)
anchor = AnchorStyle.Right;
//get a reference to the resizingpanel container of relativePane
ResizingPanel relativePaneContainer = LogicalTreeHelper.GetParent(relativePane) as ResizingPanel;
DocumentPaneResizingPanel relativeDocumentPaneContainer = relativePane.GetParentDocumentPaneResizingPanel();
@ -1083,6 +1095,9 @@ namespace AvalonDock @@ -1083,6 +1095,9 @@ namespace AvalonDock
/// <param name="anchor"></param>
public void Anchor(DockablePane paneToAnchor, DockablePane relativePane, AnchorStyle anchor)
{
if (anchor == AnchorStyle.None)
anchor = AnchorStyle.Right;
//get a refernce to the resizingpanel container of relativePane
ResizingPanel relativePaneContainer = LogicalTreeHelper.GetParent(relativePane) as ResizingPanel;
Orientation requestedOrientation =
@ -1536,7 +1551,7 @@ namespace AvalonDock @@ -1536,7 +1551,7 @@ namespace AvalonDock
/// <param name="desideredState">State desidered</param>
public void Show(DockableContent content, DockableContentState desideredState)
{
Show(content, desideredState, AnchorStyle.Right);
Show(content, desideredState, AnchorStyle.None);
}
/// <summary>
@ -1696,6 +1711,14 @@ namespace AvalonDock @@ -1696,6 +1711,14 @@ namespace AvalonDock
DockablePane newHostpane = new DockablePane();
newHostpane.Items.Add(content);
if (desideredAnchor == AnchorStyle.None &&
content.SavedStateAndPosition != null &&
content.SavedStateAndPosition.Anchor != AnchorStyle.None)
desideredAnchor = content.SavedStateAndPosition.Anchor;
if (desideredAnchor == AnchorStyle.None)
desideredAnchor = AnchorStyle.Right;
if (desideredAnchor == AnchorStyle.Left ||
desideredAnchor == AnchorStyle.Right)
{
@ -1705,7 +1728,8 @@ namespace AvalonDock @@ -1705,7 +1728,8 @@ namespace AvalonDock
!double.IsNaN(content.SavedStateAndPosition.Width))
w = content.SavedStateAndPosition.Width;
//ResizingPanel.SetResizeWidth(newHostpane, w);
ResizingPanel.SetResizeWidth(newHostpane, new GridLength(w));
ResizingPanel.SetEffectiveSize(newHostpane, new Size(w, 0.0));
}
else
{
@ -1715,7 +1739,8 @@ namespace AvalonDock @@ -1715,7 +1739,8 @@ namespace AvalonDock
!double.IsNaN(content.SavedStateAndPosition.Height))
h = content.SavedStateAndPosition.Height;
//ResizingPanel.SetResizeHeight(newHostpane, h);
ResizingPanel.SetResizeHeight(newHostpane, new GridLength(h));
ResizingPanel.SetEffectiveSize(newHostpane, new Size(0.0, h));
}
Anchor(newHostpane, desideredAnchor);
@ -2474,13 +2499,18 @@ namespace AvalonDock @@ -2474,13 +2499,18 @@ namespace AvalonDock
{
if (content.State == DockableContentState.AutoHide)
{
if ((content.Parent as DockablePane).Items.Count == 1)
DockablePane parentContainer = content.Parent as DockablePane;
if (parentContainer != null &&
parentContainer.Items.Count == 1)
ToggleAutoHide(content.Parent as DockablePane);
}
if (content.State == DockableContentState.DockableWindow ||
content.State == DockableContentState.FloatingWindow)
{
if ((content.Parent as DockablePane).Items.Count == 1)
DockablePane parentContainer = content.Parent as DockablePane;
if (parentContainer != null &&
parentContainer.Items.Count == 1)
{
FloatingWindow floatingWindow = Window.GetWindow(content) as FloatingWindow;
floatingWindow.Close();
@ -2493,6 +2523,11 @@ namespace AvalonDock @@ -2493,6 +2523,11 @@ namespace AvalonDock
content.DetachFromContainerPane();
}
public delegate void DeserializationCallbackHandler(object sender, DeserializationCallbackEventArgs e);
public DeserializationCallbackHandler DeserializationCallback { get; set; }
void ShowAllHiddenContents()
{
while (_hiddenContents.Count > 0)
@ -2502,7 +2537,7 @@ namespace AvalonDock @@ -2502,7 +2537,7 @@ namespace AvalonDock
}
}
void RestoreDocumentPaneLayout(XmlElement childElement, out DocumentPane mainExistingDocumentPane, out DocumentPaneResizingPanel existingDocumentPanel)
void RestoreDocumentPaneLayout(XmlElement childElement, out DocumentPane mainExistingDocumentPane, out DocumentPaneResizingPanel existingDocumentPanel, DockableContent[] dockableContents)
{
mainExistingDocumentPane = (Content is DocumentPane) ? Content as DocumentPane : GetMainDocumentPane(Content as ResizingPanel);
existingDocumentPanel = mainExistingDocumentPane.GetParentDocumentPaneResizingPanel();
@ -2534,17 +2569,36 @@ namespace AvalonDock @@ -2534,17 +2569,36 @@ namespace AvalonDock
{
if (contentElement.HasAttribute("Name"))
{
foreach (DockableContent content in DockableContents)
DockableContent foundContent = null;
string contentName = contentElement.GetAttribute("Name");
foreach (DockableContent content in dockableContents)
{
if (content.Name == contentElement.GetAttribute("Name"))
if (content.Name == contentName)
{
DetachContentFromDockingManager(content);
mainExistingDocumentPane.Items.Add(content);
content.SetStateToDocument();
content.RestoreLayout(contentElement);
foundContent = content;
break;
}
}
if (foundContent == null &&
DeserializationCallback != null)
{
DeserializationCallbackEventArgs e = new DeserializationCallbackEventArgs(contentName);
DeserializationCallback(this, e);
foundContent = e.Content;
}
if (foundContent != null)
{
DetachContentFromDockingManager(foundContent);
mainExistingDocumentPane.Items.Add(foundContent);
foundContent.SetStateToDocument();
//call custom layout persistence method
foundContent.RestoreLayout(contentElement);
}
}
}
}
@ -2593,23 +2647,39 @@ namespace AvalonDock @@ -2593,23 +2647,39 @@ namespace AvalonDock
{
if (contentElement.HasAttribute("Name"))
{
DockableContent foundContent = null;
string contentName = contentElement.GetAttribute("Name");
foreach (DockableContent content in dockableContents)
{
if (content.Name == contentElement.GetAttribute("Name"))
if (content.Name == contentName)
{
DetachContentFromDockingManager(content);
pane.Items.Add(content);
content.SetStateToDock();
foundContent = content;
break;
}
}
if (foundContent == null &&
DeserializationCallback != null)
{
DeserializationCallbackEventArgs e = new DeserializationCallbackEventArgs(contentName);
DeserializationCallback(this, e);
foundContent = e.Content;
}
if (foundContent != null)
{
DetachContentFromDockingManager(foundContent);
pane.Items.Add(foundContent);
foundContent.SetStateToDock();
if (contentElement.HasAttribute("AutoHide") &&
XmlConvert.ToBoolean(contentElement.GetAttribute("AutoHide")) &&
pane.Items.Count == 1)
toggleAutoHide = true;
//call custom layout persistence method
content.RestoreLayout(contentElement);
break;
}
foundContent.RestoreLayout(contentElement);
}
}
}
@ -2629,7 +2699,7 @@ namespace AvalonDock @@ -2629,7 +2699,7 @@ namespace AvalonDock
DocumentPaneResizingPanel existingDocumentPanel = null;
DocumentPane mainExistingDocumentPane = null;
RestoreDocumentPaneLayout(childElement, out mainExistingDocumentPane, out existingDocumentPanel);
RestoreDocumentPaneLayout(childElement, out mainExistingDocumentPane, out existingDocumentPanel, dockableContents);
if (existingDocumentPanel != null)
{
@ -2723,7 +2793,7 @@ namespace AvalonDock @@ -2723,7 +2793,7 @@ namespace AvalonDock
DocumentPaneResizingPanel existingDocumentPanel = null;
DocumentPane mainExistingDocumentPane = null;
RestoreDocumentPaneLayout(rootElement, out mainExistingDocumentPane, out existingDocumentPanel);
RestoreDocumentPaneLayout(rootElement, out mainExistingDocumentPane, out existingDocumentPanel, actualContents);
if (existingDocumentPanel != null)
{
@ -2776,14 +2846,24 @@ namespace AvalonDock @@ -2776,14 +2846,24 @@ namespace AvalonDock
foreach (XmlElement contentElement in paneElement.ChildNodes)
{
#region Find the content to transfer
string contentToFindName = contentElement.GetAttribute("Name");
foreach (DockableContent content in actualContents)
{
if (contentElement.GetAttribute("Name") == content.Name)
if (contentToFindName == content.Name)
{
contentToTransfer = content;
break;
}
}
if (contentToTransfer == null &&
DeserializationCallback != null)
{
DeserializationCallbackEventArgs e = new DeserializationCallbackEventArgs(contentToFindName);
DeserializationCallback(this, e);
contentToTransfer = e.Content;
}
#endregion

24
src/Libraries/AvalonDock/FloatingWindow.cs

@ -117,6 +117,29 @@ namespace AvalonDock @@ -117,6 +117,29 @@ namespace AvalonDock
}
#region Active Content Management
ManagedContent lastActiveContent = null;
protected override void OnActivated(EventArgs e)
{
if (Manager != null)
{
lastActiveContent = Manager.ActiveContent;
Manager.ActiveContent = HostedPane.SelectedItem as ManagedContent;
}
base.OnActivated(e);
}
protected override void OnDeactivated(EventArgs e)
{
if (Manager != null && lastActiveContent != null)
{
Manager.ActiveContent = lastActiveContent;
}
base.OnDeactivated(e);
}
#endregion
public abstract Pane ClonePane();
@ -368,7 +391,6 @@ namespace AvalonDock @@ -368,7 +391,6 @@ namespace AvalonDock
}
#endregion
#region INotifyPropertyChanged Members
public event PropertyChangedEventHandler PropertyChanged;

2
src/Libraries/AvalonDock/Properties/AssemblyInfo.cs

@ -59,4 +59,4 @@ using System.Runtime.InteropServices; @@ -59,4 +59,4 @@ using System.Runtime.InteropServices;
//
// You can specify all the values or you can default the Revision and Build Numbers
// by using the '*' as shown below:
[assembly: AssemblyVersion("1.2.2104")]
[assembly: AssemblyVersion("1.2.2154")]

2
src/Libraries/AvalonDock/ResizingPanel.cs

@ -789,7 +789,7 @@ namespace AvalonDock @@ -789,7 +789,7 @@ namespace AvalonDock
#if DEBUG
Debug.Assert(_splitterList.Count == Children.Count / 2);
i = 0;
while (true)
while (Children.Count > 0)
{
Debug.Assert(Children[i] != null);
Debug.Assert(!(Children[i] is ResizingPanelSplitter));

6
src/Libraries/AvalonEdit/ICSharpCode.AvalonEdit/CodeCompletion/CompletionList.cs

@ -59,7 +59,11 @@ namespace ICSharpCode.AvalonEdit.CodeCompletion @@ -59,7 +59,11 @@ namespace ICSharpCode.AvalonEdit.CodeCompletion
/// Gets the list box.
/// </summary>
public CompletionListBox ListBox {
get { return listBox; }
get {
if (listBox == null)
ApplyTemplate();
return listBox;
}
}
/// <summary>

32
src/Libraries/AvalonEdit/ICSharpCode.AvalonEdit/CodeCompletion/CompletionWindow.cs

@ -32,6 +32,7 @@ namespace ICSharpCode.AvalonEdit.CodeCompletion @@ -32,6 +32,7 @@ namespace ICSharpCode.AvalonEdit.CodeCompletion
public CompletionWindow(TextArea textArea) : base(textArea)
{
// keep height automatic
this.CloseAutomatically = true;
this.SizeToContent = SizeToContent.Height;
this.Width = 175;
this.Content = completionList;
@ -45,6 +46,7 @@ namespace ICSharpCode.AvalonEdit.CodeCompletion @@ -45,6 +46,7 @@ namespace ICSharpCode.AvalonEdit.CodeCompletion
completionList.InsertionRequested += completionList_InsertionRequested;
completionList.SelectionChanged += completionList_SelectionChanged;
AttachEvents();
}
#region ToolTip handling
@ -85,21 +87,26 @@ namespace ICSharpCode.AvalonEdit.CodeCompletion @@ -85,21 +87,26 @@ namespace ICSharpCode.AvalonEdit.CodeCompletion
{
// prevent CompletionWindow from growing too large
if (this.ActualHeight > 300) {
if (this.SizeToContent == SizeToContent.Height)
this.SizeToContent = SizeToContent.Manual;
else if (this.SizeToContent == SizeToContent.WidthAndHeight)
this.SizeToContent = SizeToContent.Width;
this.Height = 300;
}
base.OnSourceInitialized(e);
}
/// <inheritdoc/>
protected override void AttachEvents()
InputHandler myInputHandler;
void AttachEvents()
{
base.AttachEvents();
this.TextArea.Caret.PositionChanged += CaretPositionChanged;
this.TextArea.MouseWheel += textArea_MouseWheel;
this.TextArea.PreviewTextInput += textArea_PreviewTextInput;
this.TextArea.ActiveInputHandler = new InputHandler(this);
myInputHandler = new InputHandler(this);
this.TextArea.ActiveInputHandler = myInputHandler;
}
/// <inheritdoc/>
@ -109,6 +116,7 @@ namespace ICSharpCode.AvalonEdit.CodeCompletion @@ -109,6 +116,7 @@ namespace ICSharpCode.AvalonEdit.CodeCompletion
this.TextArea.MouseWheel -= textArea_MouseWheel;
this.TextArea.PreviewTextInput -= textArea_PreviewTextInput;
base.DetachEvents();
if (this.TextArea.ActiveInputHandler == myInputHandler)
this.TextArea.ActiveInputHandler = this.TextArea.DefaultInputHandler;
}
@ -185,10 +193,22 @@ namespace ICSharpCode.AvalonEdit.CodeCompletion @@ -185,10 +193,22 @@ namespace ICSharpCode.AvalonEdit.CodeCompletion
return completionList.ScrollViewer ?? completionList.ListBox ?? (UIElement)completionList;
}
/// <summary>
/// Gets/Sets whether the completion window should close automatically.
/// The default value is true.
/// </summary>
public bool CloseAutomatically { get; set; }
/// <inheritdoc/>
protected override bool CloseOnFocusLost {
get { return this.CloseAutomatically; }
}
/// <summary>
/// When this flag is set, code completion closes if the caret moves to the
/// beginning of the allowed range. This is useful in Ctrl+Space and "complete when typing",
/// but not in dot-completion.
/// Has no effect if CloseAutomatically is false.
/// </summary>
public bool CloseWhenCaretAtBeginning { get; set; }
@ -196,12 +216,14 @@ namespace ICSharpCode.AvalonEdit.CodeCompletion @@ -196,12 +216,14 @@ namespace ICSharpCode.AvalonEdit.CodeCompletion
{
int offset = this.TextArea.Caret.Offset;
if (offset == this.StartOffset) {
if (CloseWhenCaretAtBeginning)
if (CloseAutomatically && CloseWhenCaretAtBeginning)
Close();
return;
}
if (offset < this.StartOffset || offset > this.EndOffset) {
if (CloseAutomatically) {
Close();
}
} else {
TextDocument document = this.TextArea.Document;
if (document != null) {

8
src/Libraries/AvalonEdit/ICSharpCode.AvalonEdit/CodeCompletion/CompletionWindowBase.cs

@ -53,13 +53,12 @@ namespace ICSharpCode.AvalonEdit.CodeCompletion @@ -53,13 +53,12 @@ namespace ICSharpCode.AvalonEdit.CodeCompletion
this.AddHandler(MouseUpEvent, new MouseButtonEventHandler(OnMouseUp), true);
startOffset = endOffset = this.TextArea.Caret.Offset;
AttachEvents();
}
#region Event Handlers
/// <summary>
/// Attaches events to the text area.
/// </summary>
protected virtual void AttachEvents()
void AttachEvents()
{
document = this.TextArea.Document;
if (document != null) {
@ -203,7 +202,6 @@ namespace ICSharpCode.AvalonEdit.CodeCompletion @@ -203,7 +202,6 @@ namespace ICSharpCode.AvalonEdit.CodeCompletion
protected override void OnSourceInitialized(EventArgs e)
{
base.OnSourceInitialized(e);
AttachEvents();
if (document != null && this.StartOffset != this.TextArea.Caret.Offset) {
SetPosition(new TextViewPosition(document.GetLocation(this.StartOffset)));

5
src/Libraries/AvalonEdit/ICSharpCode.AvalonEdit/CodeCompletion/InsightWindow.cs

@ -31,6 +31,7 @@ namespace ICSharpCode.AvalonEdit.CodeCompletion @@ -31,6 +31,7 @@ namespace ICSharpCode.AvalonEdit.CodeCompletion
public InsightWindow(TextArea textArea) : base(textArea)
{
this.CloseAutomatically = true;
AttachEvents();
}
/// <summary>
@ -44,10 +45,8 @@ namespace ICSharpCode.AvalonEdit.CodeCompletion @@ -44,10 +45,8 @@ namespace ICSharpCode.AvalonEdit.CodeCompletion
get { return this.CloseAutomatically; }
}
/// <inheritdoc/>
protected override void AttachEvents()
void AttachEvents()
{
base.AttachEvents();
this.TextArea.Caret.PositionChanged += CaretPositionChanged;
}

2
src/Libraries/AvalonEdit/ICSharpCode.AvalonEdit/Document/NewLineFinder.cs

@ -51,6 +51,8 @@ namespace ICSharpCode.AvalonEdit.Document @@ -51,6 +51,8 @@ namespace ICSharpCode.AvalonEdit.Document
/// </summary>
public static string NormalizeNewLines(string input, string newLine)
{
if (input == null)
return null;
Debug.Assert(IsNewLine(newLine));
SimpleSegment ds = NextNewLine(input, 0);
if (ds == SimpleSegment.Invalid) // text does not contain any new lines

2
src/Libraries/AvalonEdit/ICSharpCode.AvalonEdit/Editing/EditingCommandHandler.cs

@ -344,6 +344,7 @@ namespace ICSharpCode.AvalonEdit.Editing @@ -344,6 +344,7 @@ namespace ICSharpCode.AvalonEdit.Editing
string newLine = NewLineFinder.GetNewLineFromDocument(textArea.Document, textArea.Caret.Line);
string text = NewLineFinder.NormalizeNewLines(Clipboard.GetText(), newLine);
if (!string.IsNullOrEmpty(text)) {
bool fullLine = textArea.Options.CutCopyWholeLine && Clipboard.ContainsData(LineSelectedType);
if (fullLine) {
DocumentLine currentLine = textArea.Document.GetLineByNumber(textArea.Caret.Line);
@ -351,6 +352,7 @@ namespace ICSharpCode.AvalonEdit.Editing @@ -351,6 +352,7 @@ namespace ICSharpCode.AvalonEdit.Editing
} else {
textArea.ReplaceSelectionWithText(text);
}
}
textArea.Caret.BringCaretToView();
args.Handled = true;
}

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

@ -77,9 +77,11 @@ @@ -77,9 +77,11 @@
<Compile Include="Src\Editor\CodeCompletion\CtrlSpaceCompletionItemProvider.cs" />
<Compile Include="Src\Editor\CodeCompletion\ICompletionItem.cs" />
<Compile Include="Src\Editor\CodeCompletion\ICompletionItemList.cs" />
<Compile Include="Src\Editor\CodeCompletion\ICompletionListWindow.cs" />
<Compile Include="Src\Editor\CodeCompletion\IInsightItem.cs" />
<Compile Include="Src\Editor\CodeCompletion\IInsightWindow.cs" />
<Compile Include="Src\Editor\CodeCompletion\IndexerInsightProvider.cs" />
<Compile Include="Src\Editor\CodeCompletion\ICompletionWindow.cs" />
<Compile Include="Src\Editor\CodeCompletion\MethodInsightItem.cs" />
<Compile Include="Src\Editor\CodeCompletion\MethodInsightProvider.cs" />
<Compile Include="Src\Editor\CodeCompletion\NRefactoryCodeCompletionBinding.cs" />

24
src/Main/Base/Project/Src/Editor/AvalonEdit/AvalonEditTextEditorAdapter.cs

@ -143,14 +143,6 @@ namespace ICSharpCode.SharpDevelop.Editor @@ -143,14 +143,6 @@ namespace ICSharpCode.SharpDevelop.Editor
get { return null; }
}
void ITextEditor.ShowCompletionWindow(ICSharpCode.TextEditor.Gui.CompletionWindow.ICompletionDataProvider provider, char ch)
{
}
public virtual void ShowCompletionWindow(ICompletionItemList data)
{
}
public object GetService(Type serviceType)
{
return textEditor.TextArea.GetService(serviceType);
@ -210,5 +202,21 @@ namespace ICSharpCode.SharpDevelop.Editor @@ -210,5 +202,21 @@ namespace ICSharpCode.SharpDevelop.Editor
{
return null;
}
void ITextEditor.ShowCompletionWindow(ICSharpCode.TextEditor.Gui.CompletionWindow.ICompletionDataProvider provider, char ch)
{
}
public virtual ICompletionListWindow ActiveCompletionWindow {
get {
return null;
}
}
public virtual ICompletionListWindow ShowCompletionWindow(ICompletionItemList data)
{
return null;
}
}
}

24
src/Main/Base/Project/Src/Editor/CodeCompletion/ICompletionListWindow.cs

@ -0,0 +1,24 @@ @@ -0,0 +1,24 @@
/*
* Created by SharpDevelop.
* User: Daniel
* Date: 06.06.2009
* Time: 13:08
*
* To change this template use Tools | Options | Coding | Edit Standard Headers.
*/
using System;
namespace ICSharpCode.SharpDevelop.Editor.CodeCompletion
{
/// <summary>
/// Represents the completion window showing a ICompletionItemList.
/// </summary>
public interface ICompletionListWindow : ICompletionWindow
{
/// <summary>
/// Gets/Sets the currently selected item.
/// </summary>
ICompletionItem SelectedItem { get; set; }
}
}

62
src/Main/Base/Project/Src/Editor/CodeCompletion/ICompletionWindow.cs

@ -0,0 +1,62 @@ @@ -0,0 +1,62 @@
/*
* Created by SharpDevelop.
* User: Daniel
* Date: 06.06.2009
* Time: 13:03
*
* To change this template use Tools | Options | Coding | Edit Standard Headers.
*/
using System;
namespace ICSharpCode.SharpDevelop.Editor.CodeCompletion
{
/// <summary>
/// Base interface for IInsightWindow and ICompletionListWindow.
/// </summary>
public interface ICompletionWindow
{
/// <summary>
/// Closes the window.
/// </summary>
void Close();
/// <summary>
/// Occurs after the window was closed.
/// </summary>
event EventHandler Closed;
/// <summary>
/// Gets/Sets the width of the window.
/// double.NaN is used to represent automatic width.
///
/// For the completion list window default width is a fixed number - using automatic width
/// will reduce performance when a large number of items is shown.
/// </summary>
double Width { get; set; }
/// <summary>
/// Gets/Sets the height of the window.
/// double.NaN is used to represent automatic height.
/// </summary>
double Height { get; set; }
/// <summary>
/// Gets/Sets whether the window should close automatically.
/// The default value is true.
/// </summary>
bool CloseAutomatically { get; set; }
/// <summary>
/// Gets/Sets the start of the text range in which the window stays open.
/// Has no effect if CloseAutomatically is false.
/// </summary>
int StartOffset { get; set; }
/// <summary>
/// Gets/Sets the end of the text range in which the window stays open.
/// Has no effect if CloseAutomatically is false.
/// </summary>
int EndOffset { get; set; }
}
}

30
src/Main/Base/Project/Src/Editor/CodeCompletion/IInsightWindow.cs

@ -13,7 +13,7 @@ namespace ICSharpCode.SharpDevelop.Editor.CodeCompletion @@ -13,7 +13,7 @@ namespace ICSharpCode.SharpDevelop.Editor.CodeCompletion
/// <summary>
/// Describes a set of insight items (e.g. multiple overloads of a method) to be displayed in the insight window.
/// </summary>
public interface IInsightWindow
public interface IInsightWindow : ICompletionWindow
{
/// <summary>
/// Gets the items to display.
@ -24,33 +24,5 @@ namespace ICSharpCode.SharpDevelop.Editor.CodeCompletion @@ -24,33 +24,5 @@ namespace ICSharpCode.SharpDevelop.Editor.CodeCompletion
/// Gets/Sets the item that is currently selected.
/// </summary>
IInsightItem SelectedItem { get; set; }
/// <summary>
/// Gets/Sets whether the insight window should close automatically.
/// The default value is true.
/// </summary>
bool CloseAutomatically { get; set; }
/// <summary>
/// Closes the insight window.
/// </summary>
void Close();
/// <summary>
/// Occurs after the insight window was closed.
/// </summary>
event EventHandler Closed;
/// <summary>
/// Gets/Sets the start of the text range in which the insight window stays open.
/// Has no effect if CloseAutomatically is false.
/// </summary>
int StartOffset { get; set; }
/// <summary>
/// Gets/Sets the end of the text range in which the insight window stays open.
/// Has no effect if CloseAutomatically is false.
/// </summary>
int EndOffset { get; set; }
}
}

7
src/Main/Base/Project/Src/Editor/ITextEditor.cs

@ -71,7 +71,12 @@ namespace ICSharpCode.SharpDevelop.Editor @@ -71,7 +71,12 @@ namespace ICSharpCode.SharpDevelop.Editor
string FileName { get; }
void ShowCompletionWindow(ICompletionItemList data);
ICompletionListWindow ShowCompletionWindow(ICompletionItemList data);
/// <summary>
/// Gets the completion window that is currently open.
/// </summary>
ICompletionListWindow ActiveCompletionWindow { get; }
/// <summary>
/// Open a new insight window showing the specified insight items.

2
src/Main/Base/Project/Src/Gui/Dialogs/NewFileDialog.cs

@ -505,7 +505,7 @@ namespace ICSharpCode.SharpDevelop.Gui @@ -505,7 +505,7 @@ namespace ICSharpCode.SharpDevelop.Gui
foreach (FileDescriptionTemplate newfile in item.Template.FileDescriptionTemplates) {
if (!IsFilenameAvailable(StringParser.Parse(newfile.Name))) {
MessageService.ShowError("Filename " + StringParser.Parse(newfile.Name) + " is in use.\nChoose another one");
MessageService.ShowError(string.Format("Filename {0} is in use.\nChoose another one", StringParser.Parse(newfile.Name))); // TODO : translate
return;
}
}

2
src/Main/Base/Project/Src/Gui/Pads/TaskList/TaskView.cs

@ -276,7 +276,7 @@ namespace ICSharpCode.SharpDevelop.Gui @@ -276,7 +276,7 @@ namespace ICSharpCode.SharpDevelop.Gui
ListViewItem item = new ListViewItem(new string[] {
String.Empty,
(task.Line + 1).ToString(),
task.Line.ToString(),
FormatDescription(task.Description),
fileName,
path

7
src/Main/Base/Project/Src/Services/ParserService/ParseProjectContent.cs

@ -9,8 +9,9 @@ using System; @@ -9,8 +9,9 @@ using System;
using System.Collections.Generic;
using ICSharpCode.Core;
using ICSharpCode.SharpDevelop.Dom;
using ICSharpCode.SharpDevelop.Project;
using ICSharpCode.SharpDevelop.Gui;
using ICSharpCode.SharpDevelop.Project;
using System.IO;
namespace ICSharpCode.SharpDevelop
{
@ -35,6 +36,10 @@ namespace ICSharpCode.SharpDevelop @@ -35,6 +36,10 @@ namespace ICSharpCode.SharpDevelop
}
}
public string AssemblyName {
get { return project.AssemblyName; }
}
bool initializing;
public override string ToString()

9
src/Main/Base/Project/Src/TextEditor/Gui/TextEditorAdapter.cs

@ -151,11 +151,18 @@ namespace ICSharpCode.SharpDevelop @@ -151,11 +151,18 @@ namespace ICSharpCode.SharpDevelop
}
}
public void ShowCompletionWindow(ICompletionItemList items)
public ICompletionListWindow ActiveCompletionWindow {
get {
return null;
}
}
public ICompletionListWindow ShowCompletionWindow(ICompletionItemList items)
{
if (sdtac != null) {
sdtac.ShowCompletionWindow(new CompletionItemListAdapter(items), '.');
}
return null;
}
public string GetWordBeforeCaret()

7
src/Main/ICSharpCode.SharpDevelop.Dom/Project/Src/ProjectContent/DefaultProjectContent.cs

@ -1020,5 +1020,12 @@ namespace ICSharpCode.SharpDevelop.Dom @@ -1020,5 +1020,12 @@ namespace ICSharpCode.SharpDevelop.Dom
}
}
}
/// <inheritdoc/>
public virtual string AssemblyName {
get {
return null;
}
}
}
}

7
src/Main/ICSharpCode.SharpDevelop.Dom/Project/Src/ProjectContent/IProjectContent.cs

@ -115,6 +115,13 @@ namespace ICSharpCode.SharpDevelop.Dom @@ -115,6 +115,13 @@ namespace ICSharpCode.SharpDevelop.Dom
/// Gets whether internals in the project content are visible to the other project content.
/// </summary>
bool InternalsVisibleTo(IProjectContent otherProjectContent);
/// <summary>
/// Gets the name of the assembly.
/// </summary>
string AssemblyName {
get;
}
}
[Flags]

6
src/Main/ICSharpCode.SharpDevelop.Dom/Project/Src/ProjectContent/ReflectionProjectContent.cs

@ -17,6 +17,7 @@ namespace ICSharpCode.SharpDevelop.Dom @@ -17,6 +17,7 @@ namespace ICSharpCode.SharpDevelop.Dom
public class ReflectionProjectContent : DefaultProjectContent
{
string assemblyFullName;
string assemblyName;
DomAssemblyName[] referencedAssemblyNames;
ICompilationUnit assemblyCompilationUnit;
string assemblyLocation;
@ -34,6 +35,10 @@ namespace ICSharpCode.SharpDevelop.Dom @@ -34,6 +35,10 @@ namespace ICSharpCode.SharpDevelop.Dom
}
}
public override string AssemblyName {
get { return assemblyName; }
}
/// <summary>
/// Gets the list of assembly names referenced by this project content.
/// </summary>
@ -110,6 +115,7 @@ namespace ICSharpCode.SharpDevelop.Dom @@ -110,6 +115,7 @@ namespace ICSharpCode.SharpDevelop.Dom
this.registry = registry;
this.assemblyFullName = assemblyFullName;
this.assemblyName = (assemblyFullName.IndexOf(',') > -1) ? assemblyFullName.Substring(0, assemblyFullName.IndexOf(',')) : assemblyFullName;
this.referencedAssemblyNames = referencedAssemblies;
this.assemblyLocation = assemblyLocation;
this.assemblyCompilationUnit = new DefaultCompilationUnit(this);

Loading…
Cancel
Save