diff --git a/src/AddIns/BackendBindings/CSharpBinding/Project/CSharpBinding.addin b/src/AddIns/BackendBindings/CSharpBinding/Project/CSharpBinding.addin
index b70e3a2dcf..221dddc0f8 100644
--- a/src/AddIns/BackendBindings/CSharpBinding/Project/CSharpBinding.addin
+++ b/src/AddIns/BackendBindings/CSharpBinding/Project/CSharpBinding.addin
@@ -33,6 +33,17 @@
+
+
+
+
+
diff --git a/src/AddIns/BackendBindings/CSharpBinding/Project/CSharpBinding.csproj b/src/AddIns/BackendBindings/CSharpBinding/Project/CSharpBinding.csproj
index 970be27a88..00a094c92b 100644
--- a/src/AddIns/BackendBindings/CSharpBinding/Project/CSharpBinding.csproj
+++ b/src/AddIns/BackendBindings/CSharpBinding/Project/CSharpBinding.csproj
@@ -115,6 +115,13 @@
CSharpProjectFormattingOptions.xaml
Code
+
+
+
+ CSharpOutlineContentHost.xaml
+
+
+
@@ -264,6 +271,7 @@
+
@@ -274,6 +282,7 @@
+
\ No newline at end of file
diff --git a/src/AddIns/BackendBindings/CSharpBinding/Project/Src/CSharpTextEditorExtension.cs b/src/AddIns/BackendBindings/CSharpBinding/Project/Src/CSharpTextEditorExtension.cs
index 0851efb6a9..93a886b242 100644
--- a/src/AddIns/BackendBindings/CSharpBinding/Project/Src/CSharpTextEditorExtension.cs
+++ b/src/AddIns/BackendBindings/CSharpBinding/Project/Src/CSharpTextEditorExtension.cs
@@ -24,10 +24,14 @@ using System.Reflection;
using ICSharpCode.AvalonEdit;
using CSharpBinding.FormattingStrategy;
using CSharpBinding.Refactoring;
+using CSharpBinding.OutlinePad;
using ICSharpCode.Core;
using ICSharpCode.SharpDevelop;
using ICSharpCode.SharpDevelop.Editor;
using ICSharpCode.SharpDevelop.Refactoring;
+using ICSharpCode.SharpDevelop.Gui;
+using ICSharpCode.AvalonEdit.Rendering;
+
namespace CSharpBinding
{
public class CSharpTextEditorExtension : ITextEditorExtension
@@ -46,6 +50,8 @@ namespace CSharpBinding
TextEditorOptions originalEditorOptions;
+ CSharpOutlineContentHost contentHost;
+
public void Attach(ITextEditor editor)
{
this.editor = editor;
@@ -75,6 +81,17 @@ namespace CSharpBinding
// Set TextEditor's options to same object
originalEditorOptions = textEditor.Options;
textEditor.Options = options.TextEditorOptions;
+
+ // add the outline pad
+ var textView = textEditor.TextArea.TextView;
+ if (textView != null) {
+ if (SD.Workbench != null) {
+ // add the CSharpOutlineContentHost, which manages the tree view
+ contentHost = new CSharpOutlineContentHost(editor);
+ textView.Services.AddService(typeof(IOutlineContentHost), contentHost);
+ }
+ textView.Services.AddService(typeof(CSharpTextEditorExtension), this);
+ }
}
}
@@ -83,13 +100,25 @@ namespace CSharpBinding
var textEditor = editor.GetService();
if (textEditor != null) {
var textView = textEditor.TextArea.TextView;
+
// Unregister our ITextEditorOptions instance from editor
var optionsService = textView.GetService();
if ((optionsService != null) && (optionsService == options))
textView.Services.RemoveService(typeof(ITextEditorOptions));
+
// Reset TextEditor options, too?
if ((textEditor.Options != null) && (textEditor.Options == options.TextEditorOptions))
textEditor.Options = originalEditorOptions;
+
+ // remove the outline pad
+ if (textView != null) {
+ if (contentHost != null) {
+ textView.Services.RemoveService(typeof(IOutlineContentHost));
+ contentHost.Dispose();
+ contentHost = null;
+ }
+ textView.Services.RemoveService(typeof(CSharpTextEditorExtension));
+ }
}
codeManipulation.Dispose();
diff --git a/src/AddIns/BackendBindings/CSharpBinding/Project/Src/OutlinePad/AstNodeHelper.cs b/src/AddIns/BackendBindings/CSharpBinding/Project/Src/OutlinePad/AstNodeHelper.cs
new file mode 100644
index 0000000000..c193578637
--- /dev/null
+++ b/src/AddIns/BackendBindings/CSharpBinding/Project/Src/OutlinePad/AstNodeHelper.cs
@@ -0,0 +1,524 @@
+// Copyright (c) 2014 AlphaSierraPapa for the SharpDevelop Team
+//
+// Permission is hereby granted, free of charge, to any person obtaining a copy of this
+// software and associated documentation files (the "Software"), to deal in the Software
+// without restriction, including without limitation the rights to use, copy, modify, merge,
+// publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons
+// to whom the Software is furnished to do so, subject to the following conditions:
+//
+// The above copyright notice and this permission notice shall be included in all copies or
+// substantial portions of the Software.
+//
+// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED,
+// INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR
+// PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE
+// FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR
+// OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
+// DEALINGS IN THE SOFTWARE.
+
+namespace CSharpBinding.OutlinePad
+{
+ using System;
+ using System.IO;
+ using System.Linq;
+ using System.Windows;
+ using System.Windows.Media;
+ using System.Text;
+
+ using ICSharpCode.NRefactory.CSharp;
+ using ICSharpCode.AvalonEdit.Highlighting;
+
+ internal static class AstNodeHelper {
+
+ static bool showExtendedInfos = true;
+ static bool colorizeNode = false;
+ static HighlightingColor nameSpaceHighLighting, regionHighLighting, classHighLighting, methodHighLighting, interfaceHighLighting;
+
+ static AstNodeHelper() {
+ var highlightingDefinition = HighlightingManager.Instance.GetDefinition("C#");
+
+ nameSpaceHighLighting = highlightingDefinition.NamedHighlightingColors.First( x => x.Name == "NamespaceKeywords");
+ regionHighLighting = highlightingDefinition.NamedHighlightingColors.First( x => x.Name == "Preprocessor");
+ classHighLighting = highlightingDefinition.NamedHighlightingColors.First( x => x.Name == "ReferenceTypeKeywords");
+ interfaceHighLighting = highlightingDefinition.NamedHighlightingColors.First( x => x.Name == "ReferenceTypeKeywords");
+ methodHighLighting = highlightingDefinition.NamedHighlightingColors.First( x => x.Name == "MethodCall");
+ }
+
+ private static Modifiers GetAccessModifier(AstNode node) {
+ var accessModifier = node.Children.FirstOrDefault(x => x is CSharpModifierToken &&
+ ((x as CSharpModifierToken).Modifier == Modifiers.Public ||
+ (x as CSharpModifierToken).Modifier == Modifiers.Protected ||
+ (x as CSharpModifierToken).Modifier == Modifiers.Private ||
+ (x as CSharpModifierToken).Modifier == Modifiers.Internal )) as CSharpModifierToken;
+
+ // special case: All members in an interface are public, although they have no access modifier
+ if (accessModifier == null && IsInterface(node.Parent)) {
+ return Modifiers.Public;
+ }
+ return accessModifier == null ? Modifiers.None : accessModifier.Modifier;
+ }
+
+ private static string GetParameterDeclsAsString(AstNodeCollection parameterDecls) {
+ var parameterString = new StringBuilder();
+ int current = 0;
+ foreach (var paramDecl in parameterDecls) {
+ if (paramDecl.ParameterModifier != ParameterModifier.None) {
+ parameterString.Append(paramDecl.ParameterModifier.ToString().ToLower());
+ parameterString.Append(" ");
+ }
+ parameterString.Append(paramDecl.Type.ToString());
+ parameterString.Append(" ");
+ parameterString.Append(paramDecl.Name);
+
+ if (current < (parameterDecls.Count - 1)) {
+ parameterString.Append(", ");
+ }
+ current++;
+ }
+
+ return parameterString.ToString();
+ }
+
+ private static string GetTypeParameterDeclsAsString(AstNodeCollection parameterDecls) {
+ var parameterString = new StringBuilder();
+ int current = 0;
+ foreach (var paramDecl in parameterDecls) {
+ parameterString.Append(paramDecl.NameToken.ToString());
+
+ if (current < (parameterDecls.Count - 1)) {
+ parameterString.Append(", ");
+ }
+ current++;
+ }
+
+ return parameterString.ToString();
+ }
+
+ public static bool IsAllowedNode(AstNode node) {
+ return (IsRegionStart(node)
+ || IsRegionEnd(node)
+ || IsClass(node)
+ || IsInterface(node)
+ || IsMethod(node)
+ || IsField(node)
+ || IsProperty(node)
+ || IsNameSpace(node)
+ || IsConstructor(node)
+ || IsEvent(node)
+ || IsDelegate(node)
+ || IsIndexer(node)
+ || IsEnum(node)
+ || IsEnumMember(node)
+ || IsStruct(node)
+ || IsOperator(node)
+ );
+ }
+
+ public static bool IsRegionStart(AstNode node) {
+ return (node is PreProcessorDirective && (node as PreProcessorDirective).Type == PreProcessorDirectiveType.Region);
+ }
+
+ internal static void SetRegionStartInfos(CSharpOutlineNode node, AstNode dataNode) {
+ var preProcessorNode = (PreProcessorDirective)dataNode;
+ node.ElementName = "****** " + preProcessorNode.Argument + " *****";
+ node.ForegroundBrush = (regionHighLighting.Foreground as SimpleHighlightingBrush).GetBrush(null);
+// node.Weight = regionHighLighting.FontWeight != null ? regionHighLighting.FontWeight.Value : FontWeights.Normal;
+ }
+
+ public static bool IsRegionEnd(AstNode node) {
+ return (node is PreProcessorDirective && (node as PreProcessorDirective).Type == PreProcessorDirectiveType.Endregion);
+ }
+
+ internal static void SetRegionEndInfos(CSharpOutlineNode node, AstNode dataNode) {
+ var preProcessorNode = (PreProcessorDirective)dataNode;
+ node.ElementName = "*********************";
+ node.ForegroundBrush = (regionHighLighting.Foreground as SimpleHighlightingBrush).GetBrush(null);
+// node.Weight = regionHighLighting.FontWeight != null ? regionHighLighting.FontWeight.Value : FontWeights.Normal;
+ }
+
+ public static bool IsDelegate(AstNode node) {
+ return (node is DelegateDeclaration);
+ }
+
+ internal static void SetDelegateNodeInfos(CSharpOutlineNode node, AstNode dataNode) {
+ var typeNode = (DelegateDeclaration)dataNode;
+ node.ElementName = typeNode.Name;
+ if (colorizeNode)
+ node.ForegroundBrush = Brushes.Black;
+// node.Weight = classHighLighting.FontWeight != null ? classHighLighting.FontWeight.Value : FontWeights.Normal;
+
+ switch(GetAccessModifier(dataNode)) {
+ case Modifiers.Public:
+ node.IconName = "Icons.16x16.Delegate";
+ break;
+ case Modifiers.Protected:
+ node.IconName = "Icons.16x16.ProtectedDelegate";
+ break;
+ case Modifiers.Private:
+ node.IconName = "Icons.16x16.PrivateDelegate";
+ break;
+ default:
+ node.IconName = "Icons.16x16.InternalDelegate";
+ break;
+ }
+ }
+
+ public static bool IsStruct(AstNode node) {
+ return (node is TypeDeclaration && (node as TypeDeclaration).ClassType == ClassType.Struct);
+ }
+
+ internal static void SetStructNodeInfos(CSharpOutlineNode node, AstNode dataNode) {
+ var typeNode = (TypeDeclaration)dataNode;
+ node.ElementName = typeNode.Name;
+ if (colorizeNode)
+ node.ForegroundBrush = (classHighLighting.Foreground as SimpleHighlightingBrush).GetBrush(null);
+// node.Weight = classHighLighting.FontWeight != null ? classHighLighting.FontWeight.Value : FontWeights.Normal;
+ node.IsExpanded = true;
+
+ switch(GetAccessModifier(dataNode)) {
+ case Modifiers.Public:
+ node.IconName = "Icons.16x16.Struct";
+ break;
+ case Modifiers.Protected:
+ node.IconName = "Icons.16x16.ProtectedStruct";
+ break;
+ case Modifiers.Private:
+ node.IconName = "Icons.16x16.PrivateStruct";
+ break;
+ default:
+ node.IconName = "Icons.16x16.InternalStruct";
+ break;
+ }
+ }
+
+ public static bool IsEnumMember(AstNode node) {
+ return (node is EnumMemberDeclaration);
+ }
+
+ internal static void SetEnumMemberNodeInfos(CSharpOutlineNode node, AstNode dataNode) {
+ var enumMemberNode = (EnumMemberDeclaration)dataNode;
+ node.ElementName = enumMemberNode.Name;
+ if (colorizeNode)
+ node.ForegroundBrush = Brushes.Black;
+ node.IconName = "Icons.16x16.Enum";
+ }
+
+ public static bool IsEnum(AstNode node) {
+ return (node is TypeDeclaration && (node as TypeDeclaration).ClassType == ClassType.Enum);
+ }
+
+ internal static void SetEnumNodeInfos(CSharpOutlineNode node, AstNode dataNode) {
+ var typeNode = (TypeDeclaration)dataNode;
+ node.ElementName = typeNode.Name;
+ if (colorizeNode)
+ node.ForegroundBrush = (classHighLighting.Foreground as SimpleHighlightingBrush).GetBrush(null);
+ node.IsExpanded = true;
+
+ switch(GetAccessModifier(dataNode)) {
+ case Modifiers.Public:
+ node.IconName = "Icons.16x16.Enum";
+ break;
+ case Modifiers.Protected:
+ node.IconName = "Icons.16x16.ProtectedEnum";
+ break;
+ case Modifiers.Private:
+ node.IconName = "Icons.16x16.PrivateEnum";
+ break;
+ default:
+ node.IconName = "Icons.16x16.InternalEnum";
+ break;
+ }
+ }
+
+ public static bool IsClass(AstNode node) {
+ return (node is TypeDeclaration && (node as TypeDeclaration).ClassType == ClassType.Class);
+ }
+
+ internal static void SetClassNodeInfos(CSharpOutlineNode node, AstNode dataNode) {
+ var typeNode = (TypeDeclaration)dataNode;
+ node.ElementName = typeNode.Name
+ + typeNode.LChevronToken
+ + GetTypeParameterDeclsAsString(typeNode.TypeParameters)
+ + typeNode.RChevronToken;
+ if (colorizeNode)
+ node.ForegroundBrush = (classHighLighting.Foreground as SimpleHighlightingBrush).GetBrush(null);
+// node.Weight = classHighLighting.FontWeight != null ? classHighLighting.FontWeight.Value : FontWeights.Normal;
+ node.IsExpanded = true;
+
+ switch(GetAccessModifier(dataNode)) {
+ case Modifiers.Public:
+ node.IconName = "Icons.16x16.Class";
+ break;
+ case Modifiers.Protected:
+ node.IconName = "Icons.16x16.ProtectedClass";
+ break;
+ case Modifiers.Private:
+ node.IconName = "Icons.16x16.PrivateClass";
+ break;
+ default:
+ node.IconName = "Icons.16x16.InternalClass";
+ break;
+ }
+ }
+
+ public static bool IsEvent(AstNode node) {
+ return (node is EventDeclaration);
+ }
+
+ internal static void SetEventNodeInfos(CSharpOutlineNode node, AstNode dataNode) {
+ var eventNode = (EventDeclaration)dataNode;
+ var varInitializer = eventNode.Children.FirstOrDefault(x => x is VariableInitializer) as VariableInitializer;
+ node.ElementName = (varInitializer != null)
+ ? varInitializer.Name
+ : "";
+ if (colorizeNode)
+ node.ForegroundBrush = Brushes.Black;
+
+ switch(GetAccessModifier(dataNode)) {
+ case Modifiers.Public:
+ node.IconName = "Icons.16x16.Event";
+ break;
+ case Modifiers.Protected:
+ node.IconName = "Icons.16x16.ProtectedEvent";
+ break;
+ default:
+ node.IconName = "Icons.16x16.PrivateEvent";
+ break;
+ }
+ }
+
+ public static bool IsInterface(AstNode node) {
+ return (node is TypeDeclaration && (node as TypeDeclaration).ClassType == ClassType.Interface);
+ }
+
+ internal static void SetInterfaceNodeInfos(CSharpOutlineNode node, AstNode dataNode) {
+ var typeNode = (TypeDeclaration)dataNode;
+ node.ElementName = typeNode.Name;
+ if (colorizeNode)
+ node.ForegroundBrush = (interfaceHighLighting.Foreground as SimpleHighlightingBrush).GetBrush(null);
+ node.IsExpanded = true;
+ switch(GetAccessModifier(dataNode)) {
+ case Modifiers.Public:
+ node.IconName = "Icons.16x16.Interface";
+ break;
+ case Modifiers.Protected:
+ node.IconName = "Icons.16x16.ProtectedInterface";
+ break;
+ case Modifiers.Private:
+ node.IconName = "Icons.16x16.PrivateInterface";
+ break;
+ default:
+ node.IconName = "Icons.16x16.InternalInterface";
+ break;
+ }
+ }
+
+ public static bool IsOperator(AstNode node) {
+ return (node is OperatorDeclaration);
+ }
+
+ internal static void SetOperatorNodeInfos(CSharpOutlineNode node, AstNode dataNode) {
+ var operatorNode = (OperatorDeclaration)dataNode;
+ node.ElementName = operatorNode.OperatorToken
+ + " " + operatorNode.OperatorTypeToken;
+
+ if (showExtendedInfos) {
+ node.ElementName += " " + operatorNode.LParToken
+ + GetParameterDeclsAsString(operatorNode.Parameters)
+ + operatorNode.RParToken;
+ }
+ if (colorizeNode)
+ node.ForegroundBrush = Brushes.Black;
+
+ switch(GetAccessModifier(dataNode)) {
+ case Modifiers.Public:
+ node.IconName = "Icons.16x16.Method";
+ break;
+ case Modifiers.Protected:
+ node.IconName = "Icons.16x16.ProtectedMethod";
+ break;
+ default:
+ node.IconName = "Icons.16x16.PrivateMethod";
+ break;
+ }
+ }
+
+ public static bool IsMethod(AstNode node) {
+ return (node is MethodDeclaration);
+ }
+
+ internal static void SetMethodNodeInfos(CSharpOutlineNode node, AstNode dataNode) {
+ var methodNode = (MethodDeclaration)dataNode;
+ node.ElementName = methodNode.Name;
+
+ node.ElementName += " " + methodNode.LParToken
+ + (showExtendedInfos ? GetParameterDeclsAsString(methodNode.Parameters) : "")
+ + methodNode.RParToken;
+
+ if (colorizeNode)
+ node.ForegroundBrush = (methodHighLighting.Foreground as SimpleHighlightingBrush).GetBrush(null);
+// node.Weight = methodHighLighting.FontWeight != null ? methodHighLighting.FontWeight.Value : FontWeights.Normal;
+
+ switch(GetAccessModifier(dataNode)) {
+ case Modifiers.Public:
+ node.IconName = "Icons.16x16.Method";
+ break;
+ case Modifiers.Protected:
+ node.IconName = "Icons.16x16.ProtectedMethod";
+ break;
+ default:
+ node.IconName = "Icons.16x16.PrivateMethod";
+ break;
+ }
+ }
+
+ public static bool IsField(AstNode node) {
+ return (node is FieldDeclaration);
+ }
+
+ internal static void SetFieldNodeInfos(CSharpOutlineNode node, AstNode dataNode) {
+
+ var fieldNode = (FieldDeclaration)dataNode;
+ var fieldName = new StringBuilder();
+ int current = 0;
+ foreach (var varInitializer in fieldNode.Variables) {
+ fieldName.Append(varInitializer.Name);
+
+ if (current < (fieldNode.Variables.Count - 1)) {
+ fieldName.Append(", ");
+ }
+ current++;
+ }
+
+ node.ElementName = fieldName.ToString();
+ if (colorizeNode)
+ node.ForegroundBrush = Brushes.Black;
+
+ switch(GetAccessModifier(dataNode)) {
+ case Modifiers.Public:
+ node.IconName = "Icons.16x16.Field";
+ break;
+ case Modifiers.Protected:
+ node.IconName = "Icons.16x16.ProtectedField";
+ break;
+ default:
+ node.IconName = "Icons.16x16.PrivateField";
+ break;
+ }
+ }
+
+ public static bool IsProperty(AstNode node) {
+ return (node is PropertyDeclaration);
+ }
+
+ internal static void SetPropertyNodeInfos(CSharpOutlineNode node, AstNode dataNode) {
+ var propertyNode = (PropertyDeclaration)dataNode;
+ node.ElementName = propertyNode.Name;
+ if (colorizeNode)
+ node.ForegroundBrush = Brushes.Black;
+ if (showExtendedInfos) {
+ node.ElementName += " " + propertyNode.LBraceToken
+ + " " + propertyNode.Getter.Keyword + (!string.IsNullOrEmpty(propertyNode.Getter.Keyword.ToString()) ? ";" : "")
+ + " " + propertyNode.Setter.Keyword + (!string.IsNullOrEmpty(propertyNode.Setter.Keyword.ToString()) ? ";" : "")
+ + " " + propertyNode.RBraceToken;
+ }
+ switch(GetAccessModifier(dataNode)) {
+ case Modifiers.Public:
+ node.IconName = "Icons.16x16.Property";
+ break;
+ case Modifiers.Protected:
+ node.IconName = "Icons.16x16.ProtectedProperty";
+ break;
+ default:
+ node.IconName = "Icons.16x16.PrivateProperty";
+ break;
+ }
+ }
+
+ public static bool IsIndexer(AstNode node) {
+ return (node is IndexerDeclaration);
+ }
+
+ internal static void SetIndexerNodeInfos(CSharpOutlineNode node, AstNode dataNode) {
+ var indexerNode = (IndexerDeclaration)dataNode;
+ node.ElementName = indexerNode.ReturnType.ToString() + " " + indexerNode.ThisToken.ToString()
+ + indexerNode.LBracketToken
+ + GetParameterDeclsAsString(indexerNode.Parameters)
+ + indexerNode.RBracketToken;
+ if (colorizeNode)
+ node.ForegroundBrush = Brushes.Black;
+ if (showExtendedInfos) {
+ node.ElementName += " " + indexerNode.LBraceToken
+ + " " + indexerNode.Getter.Keyword + (!string.IsNullOrEmpty(indexerNode.Getter.Keyword.ToString()) ? ";" : "")
+ + " " + indexerNode.Setter.Keyword + (!string.IsNullOrEmpty(indexerNode.Setter.Keyword.ToString()) ? ";" : "")
+ + " " + indexerNode.RBraceToken;
+ }
+ switch(GetAccessModifier(dataNode)) {
+ case Modifiers.Public:
+ node.IconName = "Icons.16x16.Property";
+ break;
+ case Modifiers.Protected:
+ node.IconName = "Icons.16x16.ProtectedProperty";
+ break;
+ default:
+ node.IconName = "Icons.16x16.PrivateProperty";
+ break;
+ }
+ }
+
+ public static bool IsNameSpace(AstNode node) {
+ return (node is NamespaceDeclaration);
+ }
+
+ internal static void SetNameSpaceNodeInfos(CSharpOutlineNode node, AstNode dataNode) {
+ var nameSpaceNode = (NamespaceDeclaration)dataNode;
+ node.ElementName = nameSpaceNode.Name;
+ node.IconName = "Icons.16x16.NameSpace";
+ node.IsExpanded = true;
+ if (colorizeNode)
+ node.ForegroundBrush = (nameSpaceHighLighting.Foreground as SimpleHighlightingBrush).GetBrush(null);
+// node.Weight = nameSpaceHighLighting.FontWeight != null ? nameSpaceHighLighting.FontWeight.Value : FontWeights.Normal;
+ }
+
+ public static bool IsConstructor(AstNode node) {
+ return (node is ConstructorDeclaration);
+ }
+
+ internal static void SetConstructorNodeInfos(CSharpOutlineNode node, AstNode dataNode) {
+ var constructorNode = (ConstructorDeclaration)dataNode;
+ node.ElementName = constructorNode.Name;
+ if (colorizeNode)
+ node.ForegroundBrush = Brushes.Black;
+
+ node.ElementName += " "
+ + constructorNode.LParToken
+ + (showExtendedInfos ? GetParameterDeclsAsString(constructorNode.Parameters) : "")
+ + constructorNode.RParToken;
+
+ switch(GetAccessModifier(dataNode)) {
+ case Modifiers.Public:
+ node.IconName = "Icons.16x16.Method";
+ break;
+ case Modifiers.Protected:
+ node.IconName = "Icons.16x16.ProtectedMethod";
+ break;
+ default:
+ node.IconName = "Icons.16x16.PrivateMethod";
+ break;
+ }
+ }
+
+ public static bool IsDocument(AstNode node) {
+ return (node is SyntaxTree);
+ }
+
+ internal static void SetDocumentNodeInfos(CSharpOutlineNode node, AstNode dataNode) {
+ node.ElementName = Path.GetFileName(((SyntaxTree)dataNode).FileName);
+ node.IconName = "C#.File.FullFile";
+ node.IsExpanded = true;
+ node.Weight = FontWeights.Bold;
+ if (colorizeNode)
+ node.ForegroundBrush = Brushes.Black;
+ }
+ }
+}
diff --git a/src/AddIns/BackendBindings/CSharpBinding/Project/Src/OutlinePad/CSharpOutlineCommands.cs b/src/AddIns/BackendBindings/CSharpBinding/Project/Src/OutlinePad/CSharpOutlineCommands.cs
new file mode 100644
index 0000000000..4815cc9211
--- /dev/null
+++ b/src/AddIns/BackendBindings/CSharpBinding/Project/Src/OutlinePad/CSharpOutlineCommands.cs
@@ -0,0 +1,128 @@
+// Copyright (c) 2014 AlphaSierraPapa for the SharpDevelop Team
+//
+// Permission is hereby granted, free of charge, to any person obtaining a copy of this
+// software and associated documentation files (the "Software"), to deal in the Software
+// without restriction, including without limitation the rights to use, copy, modify, merge,
+// publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons
+// to whom the Software is furnished to do so, subject to the following conditions:
+//
+// The above copyright notice and this permission notice shall be included in all copies or
+// substantial portions of the Software.
+//
+// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED,
+// INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR
+// PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE
+// FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR
+// OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
+// DEALINGS IN THE SOFTWARE.
+
+namespace CSharpBinding.OutlinePad
+{
+ using System;
+ using ICSharpCode.SharpDevelop;
+ using ICSharpCode.AvalonEdit.Folding;
+ using System.Linq;
+
+ ///
+ /// RemoveNodeCommand.
+ ///
+ public class RemoveNodeCommand : SimpleCommand
+ {
+ public override bool CanExecute(object parameter) {
+ var node = parameter as CSharpOutlineNode;
+ if (node == null)
+ return false;
+ if (node.StartMarker == null || node.EndMarker == null)
+ return false;
+ if (node.StartMarker.IsDeleted || node.EndMarker.IsDeleted)
+ return false;
+ if (node.EndMarker.Offset == 0)
+ return false;
+ if (node.EndMarker.Offset < node.StartMarker.Offset)
+ return false;
+ return true;
+ }
+
+ public override void Execute(object parameter) {
+ var node = parameter as CSharpOutlineNode;
+ node.Editor.Document.Remove(node.StartMarker.Offset, node.EndMarker.Offset - node.StartMarker.Offset);
+ }
+ }
+
+ ///
+ /// SelectRegionCommand.
+ ///
+ public class SelectRegionCommand : SimpleCommand
+ {
+ public override bool CanExecute(object parameter) {
+ var node = parameter as CSharpOutlineNode;
+ if (node == null)
+ return false;
+ if (node.StartMarker == null || node.EndMarker == null)
+ return false;
+ if (node.StartMarker.IsDeleted || node.EndMarker.IsDeleted)
+ return false;
+ if (node.EndMarker.Offset == 0)
+ return false;
+ if (node.EndMarker.Offset < node.StartMarker.Offset)
+ return false;
+ return true;
+ }
+
+ public override void Execute(object parameter) {
+ var node = parameter as CSharpOutlineNode;
+ node.Editor.Select(node.StartMarker.Offset, node.EndMarker.Offset - node.StartMarker.Offset);
+ }
+ }
+
+ ///
+ /// HandleFoldingCommand
+ ///
+ public class HandleFoldingCommand : SimpleCommand
+ {
+ public override bool CanExecute(object parameter) {
+ var node = parameter as CSharpOutlineNode;
+ if (node == null)
+ return false;
+ if (node.StartMarker == null || node.EndMarker == null)
+ return false;
+ if (node.StartMarker.IsDeleted || node.EndMarker.IsDeleted)
+ return false;
+ if (node.EndMarker.Offset == 0)
+ return false;
+ if (node.EndMarker.Offset < node.StartMarker.Offset)
+ return false;
+ return true;
+ }
+
+ public override void Execute(object parameter) {
+ var node = parameter as CSharpOutlineNode;
+
+ if (node == null || node.Editor == null)
+ return;
+
+ FoldingManager foldingManager = node.Editor.GetService(typeof(FoldingManager)) as FoldingManager;
+
+ if (foldingManager == null)
+ return;
+
+ // The endline is, where the first child starts. The folding has to be
+ // between the StartMarker.Line of the current node and the StartMarker.Line of the first child.
+ int endLine = node.StartMarker.Line;
+ var firstChild = node.Children.FirstOrDefault();
+ if (firstChild != null) {
+ endLine = (firstChild as CSharpOutlineNode).StartMarker.Line;
+ }
+
+ FoldingSection folding = foldingManager.GetNextFolding(node.StartMarker.Offset);
+
+ if (folding == null)
+ return;
+ // is next folding below the endline, the it belongs to a other node
+ if (node.Editor.Document.GetLineForOffset(folding.StartOffset).LineNumber >= endLine)
+ return;
+
+ folding.IsFolded = !node.IsExpanded;
+ }
+ }
+}
diff --git a/src/AddIns/BackendBindings/CSharpBinding/Project/Src/OutlinePad/CSharpOutlineContentHost.xaml b/src/AddIns/BackendBindings/CSharpBinding/Project/Src/OutlinePad/CSharpOutlineContentHost.xaml
new file mode 100644
index 0000000000..bda20483ed
--- /dev/null
+++ b/src/AddIns/BackendBindings/CSharpBinding/Project/Src/OutlinePad/CSharpOutlineContentHost.xaml
@@ -0,0 +1,13 @@
+
+
+
\ No newline at end of file
diff --git a/src/AddIns/BackendBindings/CSharpBinding/Project/Src/OutlinePad/CSharpOutlineContentHost.xaml.cs b/src/AddIns/BackendBindings/CSharpBinding/Project/Src/OutlinePad/CSharpOutlineContentHost.xaml.cs
new file mode 100644
index 0000000000..ae470525c2
--- /dev/null
+++ b/src/AddIns/BackendBindings/CSharpBinding/Project/Src/OutlinePad/CSharpOutlineContentHost.xaml.cs
@@ -0,0 +1,352 @@
+// Copyright (c) 2014 AlphaSierraPapa for the SharpDevelop Team
+//
+// Permission is hereby granted, free of charge, to any person obtaining a copy of this
+// software and associated documentation files (the "Software"), to deal in the Software
+// without restriction, including without limitation the rights to use, copy, modify, merge,
+// publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons
+// to whom the Software is furnished to do so, subject to the following conditions:
+//
+// The above copyright notice and this permission notice shall be included in all copies or
+// substantial portions of the Software.
+//
+// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED,
+// INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR
+// PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE
+// FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR
+// OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
+// DEALINGS IN THE SOFTWARE.
+
+using System;
+using System.Linq;
+using System.Windows.Controls;
+using System.Windows.Input;
+
+using ICSharpCode.Core;
+using ICSharpCode.NRefactory;
+using ICSharpCode.NRefactory.CSharp;
+using ICSharpCode.SharpDevelop;
+using ICSharpCode.SharpDevelop.Editor;
+using ICSharpCode.SharpDevelop.Gui;
+using ICSharpCode.SharpDevelop.Parser;
+using CSharpBinding.Parser;
+using System.Windows.Threading;
+using ICSharpCode.AvalonEdit.Highlighting;
+using ICSharpCode.AvalonEdit.Folding;
+
+namespace CSharpBinding.OutlinePad
+{
+ ///
+ /// Interaction logic for CSharpOutlineContentHost.xaml
+ ///
+ public partial class CSharpOutlineContentHost : DockPanel, IOutlineContentHost, IDisposable
+ {
+ ITextEditor editor;
+ DispatcherTimer updateTreeTimer = new DispatcherTimer();
+ DispatcherTimer scrollToNodeTimer = new DispatcherTimer();
+ SyntaxTree syntaxTree;
+ TextLocation? lastCaretLocation;
+ CSharpOutlineNode selectedNode = null;
+ static double refreshDelayInMilliSec = 1000;
+ static bool optionSelectActiveTreeNode = true;
+ static bool optionSelectRange = false;
+
+ public CSharpOutlineContentHost(ITextEditor editor) {
+ this.editor = editor;
+ this.editor.Caret.LocationChanged += CaretLocationChanged;
+
+ InitializeComponent();
+
+ SD.ParserService.ParseInformationUpdated += ParseInfoUpdated;
+
+ this.updateTreeTimer.Interval = TimeSpan.FromMilliseconds(refreshDelayInMilliSec);
+ this.updateTreeTimer.Tick += this.UpdateTreeTimer_Tick;
+
+ this.scrollToNodeTimer.Interval = TimeSpan.FromMilliseconds(200);
+ this.scrollToNodeTimer.Tick += this.ScrollToNodeTimer_Tick;
+ }
+
+ void ParseInfoUpdated(object sender, ParseInformationEventArgs e) {
+ if (this.editor == null || !FileUtility.IsEqualFileName(this.editor.FileName, e.FileName))
+ return;
+
+ var parseInfo = e.NewParseInformation as CSharpFullParseInformation;
+ if (parseInfo != null && parseInfo.SyntaxTree != null) {
+ this.updateTreeTimer.Stop();
+ this.syntaxTree = parseInfo.SyntaxTree;
+ this.updateTreeTimer.Start();
+ }
+ }
+
+ void CaretLocationChanged(object sender, EventArgs e)
+ {
+ SelectActiveTreeNode();
+ }
+
+ void SelectActiveTreeNode() {
+ if (!optionSelectActiveTreeNode)
+ return;
+ // prevent unnecessary looping, when both CaretLocationChanged and ParseUpdateChanged are fired.
+ if (this.lastCaretLocation.HasValue && this.lastCaretLocation == this.editor.Caret.Location)
+ return;
+ // same line, mostly in the same region, no update needed (there is a small inaccuracy, when entering a method/member)
+// if (this.lastCaretLocation.HasValue && this.lastCaretLocation.Value.Line == this.editor.Caret.Location.Line)
+// return;
+
+ this.lastCaretLocation = this.editor.Caret.Location;
+ selectedNode = null;
+ FindNodeFromLocation(this.editor.Caret.Location, treeView.Root as CSharpOutlineNode);
+ if (selectedNode != null && treeView.SelectedItem != selectedNode) {
+ treeView.SelectedItem = selectedNode;
+
+ if (!scrollToNodeTimer.IsEnabled) {
+ scrollToNodeTimer.Start();
+ }
+ }
+ }
+
+ bool IsRangeInside(TextLocation outerStartLocation, TextLocation outerEndLocation,
+ TextLocation innerStartLocation, TextLocation innerEndLocation) {
+ if (outerStartLocation.IsEmpty || outerStartLocation.IsInfinite() ||
+ outerEndLocation.IsEmpty || outerEndLocation.IsInfinite() ||
+ innerStartLocation.IsEmpty || innerStartLocation.IsInfinite() ||
+ innerEndLocation.IsEmpty || innerEndLocation.IsInfinite())
+ return false;
+
+ const int virtualLineLength = 200;
+ var outerRange = (outerEndLocation.Line - outerStartLocation.Line) * virtualLineLength - outerStartLocation.Column + outerEndLocation.Column;
+ var innerRange = (innerEndLocation.Line - innerStartLocation.Line) * virtualLineLength - innerStartLocation.Column + innerEndLocation.Column;
+ return innerRange < outerRange;
+ }
+
+ void FindNodeFromLocation(TextLocation location, CSharpOutlineNode node) {
+ if (node == null)
+ return;
+ if (node.StartMarker.IsDeleted || node.EndMarker.IsDeleted)
+ return;
+
+ if (location.IsInside(node.StartMarker.Location, node.EndMarker.Location)
+ && (selectedNode == null || IsRangeInside(selectedNode.AstNodeItem.StartLocation, selectedNode.AstNodeItem.EndLocation,
+ node.AstNodeItem.StartLocation, node.AstNodeItem.EndLocation))) {
+ selectedNode = node;
+ }
+
+ foreach(var child in node.Children) {
+ FindNodeFromLocation(location, child as CSharpOutlineNode);
+ }
+ }
+
+ void UpdateTreeTimer_Tick(Object sender, EventArgs args) {
+ this.updateTreeTimer.Stop();
+ this.UpdateTree(this.syntaxTree);
+ this.SelectActiveTreeNode();
+ }
+
+ void ScrollToNodeTimer_Tick(Object sender, EventArgs args) {
+ this.scrollToNodeTimer.Stop();
+ if (selectedNode != null) {
+ treeView.ScrollIntoView(selectedNode);
+ }
+ }
+
+ void UpdateTree(AstNode syntaxTree) {
+ if (syntaxTree == null)
+ return;
+
+ if (treeView.Root == null) {
+ treeView.Root = new CSharpOutlineNode();
+ SetNodeInfos(treeView.Root as CSharpOutlineNode, null, syntaxTree);
+ }
+
+ this.UpdateNode(treeView.Root as CSharpOutlineNode, syntaxTree);
+ }
+
+ void UpdateNode(CSharpOutlineNode node, AstNode dataNode) {
+ if (dataNode == null || node == null)
+ return;
+
+ SetNodeInfos(node, null, dataNode);
+
+ // Filter the children, for only the needed/wanted nodes
+ var dataChildren = dataNode.Children.Where(childNode => AstNodeHelper.IsAllowedNode(childNode)).ToList();
+
+ int childrenCount = node.Children.Count;
+ int dataCount = dataChildren.Count;
+
+ for (int i = 0; i < Math.Max(childrenCount, dataCount); i++) {
+ if (i >= childrenCount) {
+
+// if (AstNodeHelper.IsRegionStart(dataChildren[i])) {
+// var regionNode = new CSharpOutlineNode();
+// SetNodeInfos(regionNode, node, dataChildren[i]);
+// node.Children.Add(regionNode);
+// node = regionNode;
+// continue;
+// }
+// if (AstNodeHelper.IsRegionEnd(dataChildren[i])) {
+// node = node.Parent;
+// continue;
+// }
+
+ node.Children.Add(BuildNode(node, dataChildren[i]));
+
+ } else if (i >= dataCount) {
+ while (node.Children.Count > dataCount)
+ node.Children.RemoveAt(dataCount);
+
+ } else {
+ UpdateNode(node.Children[i] as CSharpOutlineNode, dataChildren[i]);
+ }
+ }
+ }
+
+ CSharpOutlineNode BuildNode(CSharpOutlineNode parentNode, AstNode dataNode) {
+
+ var node = new CSharpOutlineNode();
+ SetNodeInfos(node, parentNode, dataNode);
+
+ // Filter the children, for only the needed/wanted nodes
+ var dataChildren = dataNode.Children.Where(v => AstNodeHelper.IsAllowedNode(v)).ToList();
+ foreach (var child in dataChildren) {
+// if (AstNodeHelper.IsRegionStart(child)) {
+// var regionNode = new CSharpOutlineNode();
+// SetNodeInfos(regionNode, node, child);
+// node.Children.Add(regionNode);
+// node = regionNode;
+// continue;
+// }
+// if (AstNodeHelper.IsRegionEnd(child)) {
+// node = node.Parent;
+// continue;
+// }
+
+ node.Children.Add(BuildNode(node, child));
+
+ }
+ return node;
+ }
+
+ void SetNodeInfos(CSharpOutlineNode node, CSharpOutlineNode parentNode, AstNode dataNode) {
+
+ int startOffset = 0;
+ int textLength = Math.Max(editor.Document.TextLength - 1,0);
+ if (!dataNode.StartLocation.IsValid() || dataNode.StartLocation.Line > editor.Document.LineCount)
+ startOffset = 0;
+ else
+ startOffset = editor.Document.GetOffset(dataNode.StartLocation);
+
+ int endOffset = 0;
+ if (!dataNode.EndLocation.IsValid() || dataNode.EndLocation.Line > editor.Document.LineCount)
+ endOffset = textLength;
+ else
+ endOffset = editor.Document.GetOffset(dataNode.EndLocation);
+
+ node.AstNodeItem = dataNode;
+ node.StartMarker = editor.Document.CreateAnchor(MinMax(startOffset, 0, textLength));
+ node.EndMarker = editor.Document.CreateAnchor(MinMax(endOffset, 0, textLength));
+ node.Editor = editor;
+ node.Parent = parentNode;
+
+ if (AstNodeHelper.IsDocument(dataNode))
+ AstNodeHelper.SetDocumentNodeInfos(node, dataNode);
+
+ if (AstNodeHelper.IsNameSpace(dataNode))
+ AstNodeHelper.SetNameSpaceNodeInfos(node, dataNode);
+
+ if (AstNodeHelper.IsRegionStart(dataNode))
+ AstNodeHelper.SetRegionStartInfos(node, dataNode);
+
+ if (AstNodeHelper.IsRegionEnd(dataNode))
+ AstNodeHelper.SetRegionEndInfos(node, dataNode);
+
+ if (AstNodeHelper.IsClass(dataNode))
+ AstNodeHelper.SetClassNodeInfos(node, dataNode);
+
+ if (AstNodeHelper.IsInterface(dataNode))
+ AstNodeHelper.SetInterfaceNodeInfos(node, dataNode);
+
+ if (AstNodeHelper.IsConstructor(dataNode))
+ AstNodeHelper.SetConstructorNodeInfos(node, dataNode);
+
+ if (AstNodeHelper.IsField(dataNode))
+ AstNodeHelper.SetFieldNodeInfos(node, dataNode);
+
+ if (AstNodeHelper.IsProperty(dataNode))
+ AstNodeHelper.SetPropertyNodeInfos(node, dataNode);
+
+ if (AstNodeHelper.IsMethod(dataNode))
+ AstNodeHelper.SetMethodNodeInfos(node, dataNode);
+
+ if (AstNodeHelper.IsEvent(dataNode))
+ AstNodeHelper.SetEventNodeInfos(node, dataNode);
+
+ if (AstNodeHelper.IsDelegate(dataNode))
+ AstNodeHelper.SetDelegateNodeInfos(node, dataNode);
+
+ if (AstNodeHelper.IsIndexer(dataNode))
+ AstNodeHelper.SetIndexerNodeInfos(node, dataNode);
+
+ if (AstNodeHelper.IsEnum(dataNode))
+ AstNodeHelper.SetEnumNodeInfos(node, dataNode);
+
+ if (AstNodeHelper.IsEnumMember(dataNode))
+ AstNodeHelper.SetEnumMemberNodeInfos(node, dataNode);
+
+ if (AstNodeHelper.IsStruct(dataNode))
+ AstNodeHelper.SetStructNodeInfos(node, dataNode);
+
+ if (AstNodeHelper.IsOperator(dataNode))
+ AstNodeHelper.SetOperatorNodeInfos(node, dataNode);
+ }
+
+ static int MinMax(int value, int lower, int upper) {
+ return Math.Min(Math.Max(value, lower), upper);
+ }
+
+ void TreeView_MouseLeftButtonUp(object sender, System.Windows.Input.MouseButtonEventArgs e)
+ {
+ var node = treeView.SelectedItem as CSharpOutlineNode;
+ if (node == null)
+ return;
+
+ if (optionSelectRange)
+ editor.Select(node.StartMarker.Offset, node.EndMarker.Offset - node.StartMarker.Offset);
+ FileService.JumpToFilePosition(this.editor.FileName, node.AstNodeItem.StartLocation.Line, node.AstNodeItem.StartLocation.Column);
+ }
+
+ void TreeViewMouseDoubleClick(object sender, MouseButtonEventArgs e) {
+ }
+
+ public object OutlineContent {
+ get { return this; }
+ }
+
+ public void Dispose() {
+ SD.ParserService.ParseInformationUpdated -= ParseInfoUpdated;
+
+ if (this.editor != null) {
+ if (this.editor.Caret != null)
+ this.editor.Caret.LocationChanged -= CaretLocationChanged;
+ this.editor = null;
+ }
+
+ this.syntaxTree = null;
+ this.lastCaretLocation = null;
+ this.selectedNode = null;
+
+ if (this.updateTreeTimer != null) {
+ this.updateTreeTimer.Stop();
+ this.updateTreeTimer.Tick -= this.UpdateTreeTimer_Tick;
+ this.updateTreeTimer = null;
+ }
+
+ if (this.scrollToNodeTimer != null) {
+ this.scrollToNodeTimer.Stop();
+ this.scrollToNodeTimer.Tick -= this.ScrollToNodeTimer_Tick;
+ this.scrollToNodeTimer = null;
+ }
+ }
+
+
+ }
+
+}
diff --git a/src/AddIns/BackendBindings/CSharpBinding/Project/Src/OutlinePad/CSharpOutlineNode.cs b/src/AddIns/BackendBindings/CSharpBinding/Project/Src/OutlinePad/CSharpOutlineNode.cs
new file mode 100644
index 0000000000..ef4224e37b
--- /dev/null
+++ b/src/AddIns/BackendBindings/CSharpBinding/Project/Src/OutlinePad/CSharpOutlineNode.cs
@@ -0,0 +1,169 @@
+// Copyright (c) 2014 AlphaSierraPapa for the SharpDevelop Team
+//
+// Permission is hereby granted, free of charge, to any person obtaining a copy of this
+// software and associated documentation files (the "Software"), to deal in the Software
+// without restriction, including without limitation the rights to use, copy, modify, merge,
+// publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons
+// to whom the Software is furnished to do so, subject to the following conditions:
+//
+// The above copyright notice and this permission notice shall be included in all copies or
+// substantial portions of the Software.
+//
+// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED,
+// INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR
+// PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE
+// FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR
+// OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
+// DEALINGS IN THE SOFTWARE.
+
+using System;
+using System.Linq;
+using System.Windows;
+using System.Windows.Media;
+using ICSharpCode.NRefactory.Editor;
+using ICSharpCode.SharpDevelop;
+using ICSharpCode.SharpDevelop.Editor;
+using ICSharpCode.TreeView;
+using ICSharpCode.NRefactory.CSharp;
+using ICSharpCode.NRefactory.TypeSystem;
+using ICSharpCode.Core.Presentation;
+using System.Windows.Controls;
+using ICSharpCode.AvalonEdit.Folding;
+
+namespace CSharpBinding.OutlinePad
+{
+ class CSharpOutlineNode : SharpTreeNode
+ {
+ string elementName, name, iconName;
+
+ public string ElementName {
+ get { return elementName; }
+ set {
+ this.elementName = value;
+ this.RaisePropertyChanged("Text");
+ }
+ }
+
+ public string Name {
+ get { return name; }
+ set {
+ this.name = value;
+ this.RaisePropertyChanged("Text");
+ }
+ }
+
+ public override object ToolTip {
+ get { return this.GetSourceText(); }
+ }
+
+ public ITextAnchor StartMarker { get; set; }
+ public ITextAnchor EndMarker { get; set; }
+ public ITextEditor Editor { get; set; }
+ public AstNode AstNodeItem { get; set; }
+ public new CSharpOutlineNode Parent { get; set; }
+
+ public string IconName {
+ get { return iconName; }
+ set {
+ iconName = value;
+ this.RaisePropertyChanged("Icon");
+ }
+ }
+
+ public string GetSourceText() {
+ if (StartMarker.IsDeleted || EndMarker.IsDeleted)
+ return "";
+
+ return Editor.Document.GetText(StartMarker.Offset, EndMarker.Offset - StartMarker.Offset);
+ }
+
+ public override bool CanDelete(SharpTreeNode[] nodes) {
+ return nodes.OfType().All(n => n.Parent != null);
+ }
+
+ public override void Delete(SharpTreeNode[] nodes) {
+ DeleteWithoutConfirmation(nodes);
+ }
+
+ public override void DeleteWithoutConfirmation(SharpTreeNode[] nodes) {
+ foreach (CSharpOutlineNode CSharpNode in nodes.OfType()) {
+ CSharpNode.DeleteCore();
+ }
+ }
+
+ void DeleteCore()
+ {
+ Editor.Document.Remove(StartMarker.Offset, EndMarker.Offset - StartMarker.Offset);
+ }
+
+ public override object Text {
+ get { return (!string.IsNullOrEmpty(Name) ? ElementName + " (" + Name + ")" : ElementName); }
+ }
+
+ public override object Icon {
+ get { return !string.IsNullOrEmpty(this.IconName)
+ ? SD.ResourceService.GetImageSource(this.IconName)
+ : null; }
+ }
+
+ public override Brush Foreground {
+ get { return foregroundBrush ?? SystemColors.WindowTextBrush; }
+ }
+
+ Brush foregroundBrush;
+ public Brush ForegroundBrush {
+ get {
+ return foregroundBrush;
+ }
+ set {
+ foregroundBrush = value;
+ RaisePropertyChanged("Foreground");
+ }
+ }
+
+ FontWeight weight = FontWeights.Normal;
+ public FontWeight Weight {
+ get {
+ return weight;
+ }
+ set {
+ weight = value;
+ RaisePropertyChanged("FontWeight");
+ }
+ }
+ FontStyle style = FontStyles.Normal;
+ public FontStyle Style {
+ get {
+ return style;
+ }
+ set {
+ style = value;
+ RaisePropertyChanged("FontStyle");
+ }
+ }
+
+ public override FontWeight FontWeight {
+ get { return Weight; }
+ }
+
+ public override FontStyle FontStyle {
+ get { return Style; }
+ }
+
+ public override void ShowContextMenu(ContextMenuEventArgs e)
+ {
+ MenuService.ShowContextMenu(null, this, "/SharpDevelop/Pads/OutlinePad/ContextMenu/NodeActions");
+ }
+
+ protected override void OnExpanding() {
+ var cmd = new HandleFoldingCommand();
+ if (cmd.CanExecute(this))
+ cmd.Execute(this);
+ }
+ protected override void OnCollapsing() {
+ var cmd = new HandleFoldingCommand();
+ if (cmd.CanExecute(this))
+ cmd.Execute(this);
+ }
+ }
+}
diff --git a/src/AddIns/BackendBindings/CSharpBinding/Project/Src/OutlinePad/ExtensionMethods.cs b/src/AddIns/BackendBindings/CSharpBinding/Project/Src/OutlinePad/ExtensionMethods.cs
new file mode 100644
index 0000000000..0b62999986
--- /dev/null
+++ b/src/AddIns/BackendBindings/CSharpBinding/Project/Src/OutlinePad/ExtensionMethods.cs
@@ -0,0 +1,51 @@
+// Copyright (c) 2014 AlphaSierraPapa for the SharpDevelop Team
+//
+// Permission is hereby granted, free of charge, to any person obtaining a copy of this
+// software and associated documentation files (the "Software"), to deal in the Software
+// without restriction, including without limitation the rights to use, copy, modify, merge,
+// publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons
+// to whom the Software is furnished to do so, subject to the following conditions:
+//
+// The above copyright notice and this permission notice shall be included in all copies or
+// substantial portions of the Software.
+//
+// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED,
+// INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR
+// PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE
+// FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR
+// OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
+// DEALINGS IN THE SOFTWARE.
+
+namespace CSharpBinding.OutlinePad
+{
+ using System;
+ using ICSharpCode.NRefactory;
+
+ ///
+ /// Description of TextLocationExtensions.
+ ///
+ static class TextLocationExtensions {
+
+ public static bool IsInfinite(this TextLocation location) {
+ return location == null || location.Line == int.MaxValue || location.Column == int.MaxValue;
+ }
+
+ public static bool IsValid(this TextLocation location) {
+ if (location.IsEmpty)
+ return false;
+ if (location.IsInfinite())
+ return false;
+ return true;
+ }
+
+ public static bool IsInside(this TextLocation location, TextLocation startLocation, TextLocation endLocation) {
+ if (location.IsEmpty)
+ return false;
+
+ return location.Line >= startLocation.Line &&
+ (location.Line <= endLocation.Line || endLocation.Line == -1) &&
+ (location.Line != startLocation.Line || location.Column >= startLocation.Column) &&
+ (location.Line != endLocation.Line || location.Column <= endLocation.Column);
+ }
+ }
+}
diff --git a/src/Libraries/AvalonEdit/ICSharpCode.AvalonEdit/Highlighting/HighlightingColorizer.cs b/src/Libraries/AvalonEdit/ICSharpCode.AvalonEdit/Highlighting/HighlightingColorizer.cs
index 68a625745e..fef10c4f68 100644
--- a/src/Libraries/AvalonEdit/ICSharpCode.AvalonEdit/Highlighting/HighlightingColorizer.cs
+++ b/src/Libraries/AvalonEdit/ICSharpCode.AvalonEdit/Highlighting/HighlightingColorizer.cs
@@ -330,6 +330,9 @@ namespace ICSharpCode.AvalonEdit.Highlighting
// so it will always invalidate the next visual line when a folded line is constructed
// and the highlighting stack has changed.
+ if (fromLineNumber > textView.Document.LineCount || toLineNumber > textView.Document.LineCount)
+ return;
+
if (fromLineNumber == toLineNumber) {
textView.Redraw(textView.Document.GetLineByNumber(fromLineNumber));
} else {
diff --git a/src/Libraries/SharpTreeView/ICSharpCode.TreeView/SharpTreeNode.cs b/src/Libraries/SharpTreeView/ICSharpCode.TreeView/SharpTreeNode.cs
index 84426dd7e5..be50c48cff 100644
--- a/src/Libraries/SharpTreeView/ICSharpCode.TreeView/SharpTreeNode.cs
+++ b/src/Libraries/SharpTreeView/ICSharpCode.TreeView/SharpTreeNode.cs
@@ -136,6 +136,14 @@ namespace ICSharpCode.TreeView
get { return Parent != null ? Parent.Level + 1 : 0; }
}
+ public virtual FontWeight FontWeight {
+ get { return FontWeights.Normal; }
+ }
+
+ public virtual FontStyle FontStyle {
+ get { return FontStyles.Normal; }
+ }
+
public bool IsRoot
{
get { return Parent == null; }